getting_started_with_gnat.rst, [...]: Update documentation.
[platform/upstream/gcc.git] / gcc / ada / gprep.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                                G P R E P                                 --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2002-2016, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Atree;    use Atree;
27 with Csets;
28 with Errutil;
29 with Namet;    use Namet;
30 with Opt;
31 with Osint;    use Osint;
32 with Output;   use Output;
33 with Prep;     use Prep;
34 with Scng;
35 with Sinput.C;
36 with Snames;
37 with Stringt;  use Stringt;
38 with Switch;   use Switch;
39 with Types;    use Types;
40
41 with Ada.Command_Line; use Ada.Command_Line;
42 with Ada.Text_IO;      use Ada.Text_IO;
43
44 with GNAT.Case_Util;            use GNAT.Case_Util;
45 with GNAT.Command_Line;
46 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
47
48 with System.OS_Lib; use System.OS_Lib;
49
50 package body GPrep is
51
52    Copyright_Displayed : Boolean := False;
53    --  Used to prevent multiple displays of the copyright notice
54
55    ------------------------
56    -- Argument Line Data --
57    ------------------------
58
59    Unix_Line_Terminators : Boolean := False;
60    --  Set to True with option -T
61
62    type String_Array is array (Boolean) of String_Access;
63    Yes_No : constant String_Array :=
64      (False => new String'("YES"),
65       True  => new String'("NO"));
66
67    Infile_Name  : Name_Id := No_Name;
68    Outfile_Name : Name_Id := No_Name;
69    Deffile_Name : Name_Id := No_Name;
70
71    Output_Directory : Name_Id := No_Name;
72    --  Used when the specified output is an existing directory
73
74    Input_Directory : Name_Id := No_Name;
75    --  Used when the specified input and output are existing directories
76
77    Source_Ref_Pragma : Boolean := False;
78    --  Record command line options (set if -r switch set)
79
80    Text_Outfile : aliased Ada.Text_IO.File_Type;
81    Outfile      : constant File_Access := Text_Outfile'Access;
82
83    File_Name_Buffer_Initial_Size : constant := 50;
84    File_Name_Buffer : String_Access :=
85                         new String (1 .. File_Name_Buffer_Initial_Size);
86    --  A buffer to build output file names from input file names
87
88    -----------------
89    -- Subprograms --
90    -----------------
91
92    procedure Display_Copyright;
93    --  Display the copyright notice
94
95    procedure Post_Scan;
96    --  Null procedure, needed by instantiation of Scng below
97
98    package Scanner is new Scng
99      (Post_Scan,
100       Errutil.Error_Msg,
101       Errutil.Error_Msg_S,
102       Errutil.Error_Msg_SC,
103       Errutil.Error_Msg_SP,
104       Errutil.Style);
105    --  The scanner for the preprocessor
106
107    function Is_ASCII_Letter (C : Character) return Boolean;
108    --  True if C is in 'a' .. 'z' or in 'A' .. 'Z'
109
110    procedure Double_File_Name_Buffer;
111    --  Double the size of the file name buffer
112
113    procedure Preprocess_Infile_Name;
114    --  When the specified output is a directory, preprocess the infile name
115    --  for symbol substitution, to get the output file name.
116
117    procedure Process_Files;
118    --  Process the single input file or all the files in the directory tree
119    --  rooted at the input directory.
120
121    procedure Process_Command_Line_Symbol_Definition (S : String);
122    --  Process a -D switch on the command line
123
124    procedure Put_Char_To_Outfile (C : Character);
125    --  Output one character to the output file. Used to initialize the
126    --  preprocessor.
127
128    procedure New_EOL_To_Outfile;
129    --  Output a new line to the output file. Used to initialize the
130    --  preprocessor.
131
132    procedure Scan_Command_Line;
133    --  Scan the switches and the file names
134
135    procedure Usage;
136    --  Display the usage
137
138    -----------------------
139    -- Display_Copyright --
140    -----------------------
141
142    procedure Display_Copyright is
143    begin
144       if not Copyright_Displayed then
145          Display_Version ("GNAT Preprocessor", "1996");
146          Copyright_Displayed := True;
147       end if;
148    end Display_Copyright;
149
150    -----------------------------
151    -- Double_File_Name_Buffer --
152    -----------------------------
153
154    procedure Double_File_Name_Buffer is
155       New_Buffer : constant String_Access :=
156                      new String (1 .. 2 * File_Name_Buffer'Length);
157    begin
158       New_Buffer (File_Name_Buffer'Range) := File_Name_Buffer.all;
159       Free (File_Name_Buffer);
160       File_Name_Buffer := New_Buffer;
161    end Double_File_Name_Buffer;
162
163    --------------
164    -- Gnatprep --
165    --------------
166
167    procedure Gnatprep is
168    begin
169       --  Do some initializations (order is important here)
170
171       Csets.Initialize;
172       Snames.Initialize;
173       Stringt.Initialize;
174       Prep.Initialize;
175
176       --  Initialize the preprocessor
177
178       Prep.Setup_Hooks
179         (Error_Msg         => Errutil.Error_Msg'Access,
180          Scan              => Scanner.Scan'Access,
181          Set_Ignore_Errors => Errutil.Set_Ignore_Errors'Access,
182          Put_Char          => Put_Char_To_Outfile'Access,
183          New_EOL           => New_EOL_To_Outfile'Access);
184
185       --  Set the scanner characteristics for the preprocessor
186
187       Scanner.Set_Special_Character ('#');
188       Scanner.Set_Special_Character ('$');
189       Scanner.Set_End_Of_Line_As_Token (True);
190
191       --  Initialize the mapping table of symbols to values
192
193       Prep.Symbol_Table.Init (Prep.Mapping);
194
195       --  Parse the switches and arguments
196
197       Scan_Command_Line;
198
199       if Opt.Verbose_Mode then
200          Display_Copyright;
201       end if;
202
203       --  Test we had all the arguments needed
204
205       if Infile_Name = No_Name then
206
207          --  No input file specified, just output the usage and exit
208
209          if Argument_Count = 0 then
210             Usage;
211          else
212             GNAT.Command_Line.Try_Help;
213          end if;
214
215          return;
216
217       elsif Outfile_Name = No_Name then
218
219          --  No output file specified, exit
220
221          GNAT.Command_Line.Try_Help;
222          return;
223       end if;
224
225       --  If a pragma Source_File_Name, we need to keep line numbers. So, if
226       --  the deleted lines are not put as comment, we must output them as
227       --  blank lines.
228
229       if Source_Ref_Pragma and (not Opt.Comment_Deleted_Lines) then
230          Opt.Blank_Deleted_Lines := True;
231       end if;
232
233       --  If we have a definition file, parse it
234
235       if Deffile_Name /= No_Name then
236          declare
237             Deffile : Source_File_Index;
238
239          begin
240             Errutil.Initialize;
241             Deffile := Sinput.C.Load_File (Get_Name_String (Deffile_Name));
242
243             --  Set Main_Source_File to the definition file for the benefit of
244             --  Errutil.Finalize.
245
246             Sinput.Main_Source_File := Deffile;
247
248             if Deffile = No_Source_File then
249                Fail ("unable to find definition file """
250                      & Get_Name_String (Deffile_Name)
251                      & """");
252             end if;
253
254             Scanner.Initialize_Scanner (Deffile);
255
256             Prep.Parse_Def_File;
257          end;
258       end if;
259
260       --  If there are errors in the definition file, output them and exit
261
262       if Total_Errors_Detected > 0 then
263          Errutil.Finalize (Source_Type => "definition");
264          Fail ("errors in definition file """
265                & Get_Name_String (Deffile_Name)
266                & """");
267       end if;
268
269       --  If -s switch was specified, print a sorted list of symbol names and
270       --  values, if any.
271
272       if Opt.List_Preprocessing_Symbols then
273          Prep.List_Symbols (Foreword => "");
274       end if;
275
276       Output_Directory := No_Name;
277       Input_Directory  := No_Name;
278
279       --  Check if the specified output is an existing directory
280
281       if Is_Directory (Get_Name_String (Outfile_Name)) then
282          Output_Directory := Outfile_Name;
283
284          --  As the output is an existing directory, check if the input too
285          --  is a directory.
286
287          if Is_Directory (Get_Name_String (Infile_Name)) then
288             Input_Directory := Infile_Name;
289          end if;
290       end if;
291
292       --  And process the single input or the files in the directory tree
293       --  rooted at the input directory.
294
295       Process_Files;
296    end Gnatprep;
297
298    ---------------------
299    -- Is_ASCII_Letter --
300    ---------------------
301
302    function Is_ASCII_Letter (C : Character) return Boolean is
303    begin
304       return C in 'A' .. 'Z' or else C in 'a' .. 'z';
305    end Is_ASCII_Letter;
306
307    ------------------------
308    -- New_EOL_To_Outfile --
309    ------------------------
310
311    procedure New_EOL_To_Outfile is
312    begin
313       New_Line (Outfile.all);
314    end New_EOL_To_Outfile;
315
316    ---------------
317    -- Post_Scan --
318    ---------------
319
320    procedure Post_Scan is
321    begin
322       null;
323    end Post_Scan;
324
325    ----------------------------
326    -- Preprocess_Infile_Name --
327    ----------------------------
328
329    procedure Preprocess_Infile_Name is
330       Len    : Natural;
331       First  : Positive;
332       Last   : Natural;
333       Symbol : Name_Id;
334       Data   : Symbol_Data;
335
336    begin
337       --  Initialize the buffer with the name of the input file
338
339       Get_Name_String (Infile_Name);
340       Len := Name_Len;
341
342       while File_Name_Buffer'Length < Len loop
343          Double_File_Name_Buffer;
344       end loop;
345
346       File_Name_Buffer (1 .. Len) := Name_Buffer (1 .. Len);
347
348       --  Look for possible symbols in the file name
349
350       First := 1;
351       while First < Len loop
352
353          --  A symbol starts with a dollar sign followed by a letter
354
355          if File_Name_Buffer (First) = '$' and then
356            Is_ASCII_Letter (File_Name_Buffer (First + 1))
357          then
358             Last := First + 1;
359
360             --  Find the last letter of the symbol
361
362             while Last < Len and then
363                Is_ASCII_Letter (File_Name_Buffer (Last + 1))
364             loop
365                Last := Last + 1;
366             end loop;
367
368             --  Get the symbol name id
369
370             Name_Len := Last - First;
371             Name_Buffer (1 .. Name_Len) :=
372               File_Name_Buffer (First + 1 .. Last);
373             To_Lower (Name_Buffer (1 .. Name_Len));
374             Symbol := Name_Find;
375
376             --  And look for this symbol name in the symbol table
377
378             for Index in 1 .. Symbol_Table.Last (Mapping) loop
379                Data := Mapping.Table (Index);
380
381                if Data.Symbol = Symbol then
382
383                   --  We found the symbol. If its value is not a string,
384                   --  replace the symbol in the file name with the value of
385                   --  the symbol.
386
387                   if not Data.Is_A_String then
388                      String_To_Name_Buffer (Data.Value);
389
390                      declare
391                         Sym_Len : constant Positive := Last - First + 1;
392                         Offset  : constant Integer := Name_Len - Sym_Len;
393                         New_Len : constant Natural := Len + Offset;
394
395                      begin
396                         while New_Len > File_Name_Buffer'Length loop
397                            Double_File_Name_Buffer;
398                         end loop;
399
400                         File_Name_Buffer (Last + 1 + Offset .. New_Len) :=
401                           File_Name_Buffer (Last + 1 .. Len);
402                         Len := New_Len;
403                         Last := Last + Offset;
404                         File_Name_Buffer (First .. Last) :=
405                           Name_Buffer (1 .. Name_Len);
406                      end;
407                   end if;
408
409                   exit;
410                end if;
411             end loop;
412
413             --  Skip over the symbol name or its value: we are not checking
414             --  for another symbol name in the value.
415
416             First := Last + 1;
417
418          else
419             First := First + 1;
420          end if;
421       end loop;
422
423       --  We now have the output file name in the buffer. Get the output
424       --  path and put it in Outfile_Name.
425
426       Get_Name_String (Output_Directory);
427       Add_Char_To_Name_Buffer (Directory_Separator);
428       Add_Str_To_Name_Buffer (File_Name_Buffer (1 .. Len));
429       Outfile_Name := Name_Find;
430    end Preprocess_Infile_Name;
431
432    --------------------------------------------
433    -- Process_Command_Line_Symbol_Definition --
434    --------------------------------------------
435
436    procedure Process_Command_Line_Symbol_Definition (S : String) is
437       Data   : Symbol_Data;
438       Symbol : Symbol_Id;
439
440    begin
441       --  Check the symbol definition and get the symbol and its value.
442       --  Fail if symbol definition is illegal.
443
444       Check_Command_Line_Symbol_Definition (S, Data);
445
446       Symbol := Index_Of (Data.Symbol);
447
448       --  If symbol does not already exist, create a new entry in the mapping
449       --  table.
450
451       if Symbol = No_Symbol then
452          Symbol_Table.Increment_Last (Mapping);
453          Symbol := Symbol_Table.Last (Mapping);
454       end if;
455
456       Mapping.Table (Symbol) := Data;
457    end Process_Command_Line_Symbol_Definition;
458
459    -------------------
460    -- Process_Files --
461    -------------------
462
463    procedure Process_Files is
464
465       procedure Process_One_File;
466       --  Process input file Infile_Name and put the result in file
467       --  Outfile_Name.
468
469       procedure Recursive_Process (In_Dir : String; Out_Dir : String);
470       --  Process recursively files in In_Dir. Results go to Out_Dir
471
472       ----------------------
473       -- Process_One_File --
474       ----------------------
475
476       procedure Process_One_File is
477          Infile : Source_File_Index;
478
479          Modified : Boolean;
480          pragma Warnings (Off, Modified);
481
482       begin
483          --  Create the output file (fails if this does not work)
484
485          begin
486             Create
487               (File => Text_Outfile,
488                Mode => Out_File,
489                Name => Get_Name_String (Outfile_Name),
490                Form => "Text_Translation=" &
491                        Yes_No (Unix_Line_Terminators).all);
492
493          exception
494             when others =>
495                Fail
496                  ("unable to create output file """
497                   & Get_Name_String (Outfile_Name)
498                   & """");
499          end;
500
501          --  Load the input file
502
503          Infile := Sinput.C.Load_File (Get_Name_String (Infile_Name));
504
505          if Infile = No_Source_File then
506             Fail ("unable to find input file """
507                   & Get_Name_String (Infile_Name)
508                   & """");
509          end if;
510
511          --  Set Main_Source_File to the input file for the benefit of
512          --  Errutil.Finalize.
513
514          Sinput.Main_Source_File := Infile;
515
516          Scanner.Initialize_Scanner (Infile);
517
518          --  Output the pragma Source_Reference if asked to
519
520          if Source_Ref_Pragma then
521             Put_Line
522               (Outfile.all,
523                "pragma Source_Reference (1, """ &
524                  Get_Name_String (Sinput.Full_File_Name (Infile)) & """);");
525          end if;
526
527          --  Preprocess the input file
528
529          Prep.Preprocess (Modified);
530
531          --  In verbose mode, if there is no error, report it
532
533          if Opt.Verbose_Mode and then Total_Errors_Detected = 0 then
534             Errutil.Finalize (Source_Type => "input");
535          end if;
536
537          --  If we had some errors, delete the output file, and report them
538
539          if Total_Errors_Detected > 0 then
540             if Outfile /= Standard_Output then
541                Delete (Text_Outfile);
542             end if;
543
544             Errutil.Finalize (Source_Type => "input");
545
546             OS_Exit (0);
547
548          --  Otherwise, close the output file, and we are done
549
550          elsif Outfile /= Standard_Output then
551             Close (Text_Outfile);
552          end if;
553       end Process_One_File;
554
555       -----------------------
556       -- Recursive_Process --
557       -----------------------
558
559       procedure Recursive_Process (In_Dir : String; Out_Dir : String) is
560          Dir_In : Dir_Type;
561          Name : String (1 .. 255);
562          Last : Natural;
563          In_Dir_Name  : Name_Id;
564          Out_Dir_Name : Name_Id;
565
566          procedure Set_Directory_Names;
567          --  Establish or reestablish the current input and output directories
568
569          -------------------------
570          -- Set_Directory_Names --
571          -------------------------
572
573          procedure Set_Directory_Names is
574          begin
575             Input_Directory := In_Dir_Name;
576             Output_Directory := Out_Dir_Name;
577          end Set_Directory_Names;
578
579       --  Start of processing for Recursive_Process
580
581       begin
582          --  Open the current input directory
583
584          begin
585             Open (Dir_In, In_Dir);
586
587          exception
588             when Directory_Error =>
589                Fail ("could not read directory " & In_Dir);
590          end;
591
592          --  Set the new input and output directory names
593
594          Name_Len := In_Dir'Length;
595          Name_Buffer (1 .. Name_Len) := In_Dir;
596          In_Dir_Name := Name_Find;
597          Name_Len := Out_Dir'Length;
598          Name_Buffer (1 .. Name_Len) := Out_Dir;
599          Out_Dir_Name := Name_Find;
600
601          Set_Directory_Names;
602
603          --  Traverse the input directory
604          loop
605             Read (Dir_In, Name, Last);
606             exit when Last = 0;
607
608             if Name (1 .. Last) /= "." and then Name (1 .. Last) /= ".." then
609                declare
610                   Input : constant String :=
611                             In_Dir & Directory_Separator & Name (1 .. Last);
612                   Output : constant String :=
613                              Out_Dir & Directory_Separator & Name (1 .. Last);
614
615                begin
616                   --  If input is an ordinary file, process it
617
618                   if Is_Regular_File (Input) then
619                      --  First get the output file name
620
621                      Name_Len := Last;
622                      Name_Buffer (1 .. Name_Len) := Name (1 .. Last);
623                      Infile_Name := Name_Find;
624                      Preprocess_Infile_Name;
625
626                      --  Set the input file name and process the file
627
628                      Name_Len := Input'Length;
629                      Name_Buffer (1 .. Name_Len) := Input;
630                      Infile_Name := Name_Find;
631                      Process_One_File;
632
633                   elsif Is_Directory (Input) then
634                      --  Input is a directory. If the corresponding output
635                      --  directory does not already exist, create it.
636
637                      if not Is_Directory (Output) then
638                         begin
639                            Make_Dir (Dir_Name => Output);
640
641                         exception
642                            when Directory_Error =>
643                               Fail ("could not create directory """
644                                     & Output
645                                     & """");
646                         end;
647                      end if;
648
649                      --  And process this new input directory
650
651                      Recursive_Process (Input, Output);
652
653                      --  Reestablish the input and output directory names
654                      --  that have been modified by the recursive call.
655
656                      Set_Directory_Names;
657                   end if;
658                end;
659             end if;
660          end loop;
661       end Recursive_Process;
662
663    --  Start of processing for Process_Files
664
665    begin
666       if Output_Directory = No_Name then
667
668          --  If the output is not a directory, fail if the input is
669          --  an existing directory, to avoid possible problems.
670
671          if Is_Directory (Get_Name_String (Infile_Name)) then
672             Fail ("input file """ & Get_Name_String (Infile_Name) &
673                   """ is a directory");
674          end if;
675
676          --  Just process the single input file
677
678          Process_One_File;
679
680       elsif Input_Directory = No_Name then
681
682          --  Get the output file name from the input file name, and process
683          --  the single input file.
684
685          Preprocess_Infile_Name;
686          Process_One_File;
687
688       else
689          --  Recursively process files in the directory tree rooted at the
690          --  input directory.
691
692          Recursive_Process
693            (In_Dir => Get_Name_String (Input_Directory),
694             Out_Dir => Get_Name_String (Output_Directory));
695       end if;
696    end Process_Files;
697
698    -------------------------
699    -- Put_Char_To_Outfile --
700    -------------------------
701
702    procedure Put_Char_To_Outfile (C : Character) is
703    begin
704       Put (Outfile.all, C);
705    end Put_Char_To_Outfile;
706
707    -----------------------
708    -- Scan_Command_Line --
709    -----------------------
710
711    procedure Scan_Command_Line is
712       Switch : Character;
713
714       procedure Check_Version_And_Help is new Check_Version_And_Help_G (Usage);
715
716       --  Start of processing for Scan_Command_Line
717
718    begin
719       --  First check for --version or --help
720
721       Check_Version_And_Help ("GNATPREP", "1996");
722
723       --  Now scan the other switches
724
725       GNAT.Command_Line.Initialize_Option_Scan;
726
727       loop
728          begin
729             Switch := GNAT.Command_Line.Getopt ("D: a b c C r s T u v");
730
731             case Switch is
732                when ASCII.NUL =>
733                   exit;
734
735                when 'D' =>
736                   Process_Command_Line_Symbol_Definition
737                     (S => GNAT.Command_Line.Parameter);
738
739                when 'a' =>
740                   Opt.No_Deletion := True;
741                   Opt.Undefined_Symbols_Are_False := True;
742
743                when 'b' =>
744                   Opt.Blank_Deleted_Lines := True;
745
746                when 'c' =>
747                   Opt.Comment_Deleted_Lines := True;
748
749                when 'C' =>
750                   Opt.Replace_In_Comments := True;
751
752                when 'r' =>
753                   Source_Ref_Pragma := True;
754
755                when 's' =>
756                   Opt.List_Preprocessing_Symbols := True;
757
758                when 'T' =>
759                   Unix_Line_Terminators := True;
760
761                when 'u' =>
762                   Opt.Undefined_Symbols_Are_False := True;
763
764                when 'v' =>
765                   Opt.Verbose_Mode := True;
766
767                when others =>
768                   Fail ("Invalid Switch: -" & Switch);
769             end case;
770
771          exception
772             when GNAT.Command_Line.Invalid_Switch =>
773                Write_Str ("Invalid Switch: -");
774                Write_Line (GNAT.Command_Line.Full_Switch);
775                GNAT.Command_Line.Try_Help;
776                OS_Exit (1);
777          end;
778       end loop;
779
780       --  Get the file names
781
782       loop
783          declare
784             S : constant String := GNAT.Command_Line.Get_Argument;
785
786          begin
787             exit when S'Length = 0;
788
789             Name_Len := S'Length;
790             Name_Buffer (1 .. Name_Len) := S;
791
792             if Infile_Name = No_Name then
793                Infile_Name := Name_Find;
794             elsif Outfile_Name = No_Name then
795                Outfile_Name := Name_Find;
796             elsif Deffile_Name = No_Name then
797                Deffile_Name := Name_Find;
798             else
799                Fail ("too many arguments specified");
800             end if;
801          end;
802       end loop;
803    end Scan_Command_Line;
804
805    -----------
806    -- Usage --
807    -----------
808
809    procedure Usage is
810    begin
811       Display_Copyright;
812       Write_Line ("Usage: gnatprep [-bcrsuv] [-Dsymbol=value] " &
813                     "infile outfile [deffile]");
814       Write_Eol;
815       Write_Line ("  infile     Name of the input file");
816       Write_Line ("  outfile    Name of the output file");
817       Write_Line ("  deffile    Name of the definition file");
818       Write_Eol;
819       Write_Line ("gnatprep switches:");
820       Display_Usage_Version_And_Help;
821       Write_Line ("   -b  Replace preprocessor lines by blank lines");
822       Write_Line ("   -c  Keep preprocessor lines as comments");
823       Write_Line ("   -C  Do symbol replacements within comments");
824       Write_Line ("   -D  Associate symbol with value");
825       Write_Line ("   -r  Generate Source_Reference pragma");
826       Write_Line ("   -s  Print a sorted list of symbol names and values");
827       Write_Line ("   -T  Use LF as line terminators");
828       Write_Line ("   -u  Treat undefined symbols as FALSE");
829       Write_Line ("   -v  Verbose mode");
830       Write_Eol;
831    end Usage;
832
833 end GPrep;