OSDN Git Service

Delete all lines containing "$Revision:".
[pf3gnuchains/gcc-fork.git] / gcc / ada / gnatcmd.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                              G N A T C M D                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --                                                                          --
10 --          Copyright (C) 1996-2002 Free Software Foundation, Inc.          --
11 --                                                                          --
12 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
13 -- terms of the  GNU General Public License as published  by the Free Soft- --
14 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
15 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
18 -- for  more details.  You should have  received  a copy of the GNU General --
19 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
20 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
21 -- MA 02111-1307, USA.                                                      --
22 --                                                                          --
23 -- GNAT was originally developed  by the GNAT team at  New York University. --
24 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
25 --                                                                          --
26 ------------------------------------------------------------------------------
27
28 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
29
30 with Csets;
31 with MLib.Tgt;
32 with MLib.Utl;
33 with Namet;    use Namet;
34 with Opt;
35 with Osint;    use Osint;
36 with Output;
37 with Prj;      use Prj;
38 with Prj.Env;
39 with Prj.Ext;  use Prj.Ext;
40 with Prj.Pars;
41 with Prj.Util; use Prj.Util;
42 with Sdefault; use Sdefault;
43 with Snames;   use Snames;
44 with Stringt;  use Stringt;
45 with Table;
46 with Types;    use Types;
47 with Hostparm; use Hostparm;
48 --  Used to determine if we are in VMS or not for error message purposes
49
50 with Ada.Characters.Handling; use Ada.Characters.Handling;
51 with Ada.Command_Line;        use Ada.Command_Line;
52 with Ada.Text_IO;             use Ada.Text_IO;
53
54 with Gnatvsn;
55 with GNAT.OS_Lib;             use GNAT.OS_Lib;
56
57 with Table;
58
59 procedure GNATCmd is
60    pragma Ident (Gnatvsn.Gnat_Version_String);
61
62    Ada_Include_Path : constant String := "ADA_INCLUDE_PATH";
63    Ada_Objects_Path : constant String := "ADA_OBJECTS_PATH";
64
65    Project_File      : String_Access;
66    Project           : Prj.Project_Id;
67    Current_Verbosity : Prj.Verbosity := Prj.Default;
68    Tool_Package_Name : Name_Id       := No_Name;
69
70    --  This flag indicates a switch -p (for gnatxref and gnatfind) for
71    --  an old fashioned project file. -p cannot be used in conjonction
72    --  with -P.
73
74    Old_Project_File_Used : Boolean := False;
75
76    --  A table to keep the switches on the command line
77
78    package Last_Switches is new Table.Table
79      (Table_Component_Type => String_Access,
80       Table_Index_Type     => Integer,
81       Table_Low_Bound      => 1,
82       Table_Initial        => 20,
83       Table_Increment      => 100,
84       Table_Name           => "Gnatcmd.Last_Switches");
85
86    --  A table to keep the switches from the project file
87
88    package First_Switches is new Table.Table
89      (Table_Component_Type => String_Access,
90       Table_Index_Type     => Integer,
91       Table_Low_Bound      => 1,
92       Table_Initial        => 20,
93       Table_Increment      => 100,
94       Table_Name           => "Gnatcmd.First_Switches");
95
96    ------------------
97    -- SWITCH TABLE --
98    ------------------
99
100    --  The switch tables contain an entry for each switch recognized by the
101    --  command processor. The syntax of entries is as follows:
102
103    --    SWITCH_STRING ::= "/ command-qualifier-name TRANSLATION"
104
105    --    TRANSLATION ::=
106    --      DIRECT_TRANSLATION
107    --    | DIRECTORIES_TRANSLATION
108    --    | FILE_TRANSLATION
109    --    | NO_SPACE_FILE_TRANSL
110    --    | NUMERIC_TRANSLATION
111    --    | STRING_TRANSLATION
112    --    | OPTIONS_TRANSLATION
113    --    | COMMANDS_TRANSLATION
114    --    | ALPHANUMPLUS_TRANSLATION
115    --    | OTHER_TRANSLATION
116
117    --    DIRECT_TRANSLATION       ::= space UNIX_SWITCHES
118    --    DIRECTORIES_TRANSLATION  ::= =* UNIX_SWITCH *
119    --    DIRECTORY_TRANSLATION    ::= =% UNIX_SWITCH %
120    --    FILE_TRANSLATION         ::= =@ UNIX_SWITCH @
121    --    NO_SPACE_FILE_TRANSL     ::= =< UNIX_SWITCH >
122    --    NUMERIC_TRANSLATION      ::= =# UNIX_SWITCH # | # number #
123    --    STRING_TRANSLATION       ::= =" UNIX_SWITCH "
124    --    OPTIONS_TRANSLATION      ::= =OPTION {space OPTION}
125    --    COMMANDS_TRANSLATION     ::= =? ARGS space command-name
126    --    ALPHANUMPLUS_TRANSLATION ::= =| UNIX_SWITCH |
127
128    --    UNIX_SWITCHES ::= UNIX_SWITCH {, UNIX_SWITCH}
129
130    --    UNIX_SWITCH ::= unix-switch-string | !unix-switch-string | `string'
131
132    --    OPTION ::= option-name space UNIX_SWITCHES
133
134    --    ARGS ::= -cargs | -bargs | -largs
135
136    --  Here command-qual is the name of the switch recognized by the GNATCmd.
137    --  This is always given in upper case in the templates, although in the
138    --  actual commands, either upper or lower case is allowed.
139
140    --  The unix-switch-string always starts with a minus, and has no commas
141    --  or spaces in it. Case is significant in the unix switch string. If a
142    --  unix switch string is preceded by the not sign (!) it means that the
143    --  effect of the corresponding command qualifer is to remove any previous
144    --  occurrence of the given switch in the command line.
145
146    --  The DIRECTORIES_TRANSLATION format is used where a list of directories
147    --  is given. This possible corresponding formats recognized by GNATCmd are
148    --  as shown by the following example for the case of PATH
149
150    --    PATH=direc
151    --    PATH=(direc,direc,direc,direc)
152
153    --  When more than one directory is present for the DIRECTORIES case, then
154    --  multiple instances of the corresponding unix switch are generated,
155    --  with the file name being substituted for the occurrence of *.
156
157    --  The FILE_TRANSLATION format is similar except that only a single
158    --  file is allowed, not a list of files, and only one unix switch is
159    --  generated as a result.
160
161    --  the NO_SPACE_FILE_TRANSL is similar to FILE_TRANSLATION, except that
162    --  no space is inserted between the switch and the file name.
163
164    --  The NUMERIC_TRANSLATION format is similar to the FILE_TRANSLATION case
165    --  except that the parameter is a decimal integer in the range 0 to 999.
166
167    --  For the OPTIONS_TRANSLATION case, GNATCmd similarly permits one or
168    --  more options to appear (although only in some cases does the use of
169    --  multiple options make logical sense). For example, taking the
170    --  case of ERRORS for GCC, the following are all allowed:
171
172    --    /ERRORS=BRIEF
173    --    /ERRORS=(FULL,VERBOSE)
174    --    /ERRORS=(BRIEF IMMEDIATE)
175
176    --  If no option is provided (e.g. just /ERRORS is written), then the
177    --  first option in the list is the default option. For /ERRORS this
178    --  is NORMAL, so /ERRORS with no option is equivalent to /ERRORS=NORMAL.
179
180    --  The COMMANDS_TRANSLATION case is only used for gnatmake, to correspond
181    --  to the use of -cargs, -bargs and -largs (the ARGS string as indicated
182    --  is one of these three possibilities). The name given by COMMAND is the
183    --  corresponding command name to be used to interprete the switches to be
184    --  passed on. Switches of this type set modes, e.g. /COMPILER_QUALIFIERS
185    --  sets the mode so that all subsequent switches, up to another switch
186    --  with COMMANDS_TRANSLATION apply to the corresponding commands issued
187    --  by the make utility. For example
188
189    --    /COMPILER_QUALIFIERS /LIST /BINDER_QUALIFIERS /MAIN
190    --    /COMPILER_QUALIFIERS /NOLIST /COMPILE_CHECKS=SYNTAX
191
192    --  Clearly these switches must come at the end of the list of switches
193    --  since all subsequent switches apply to an issued command.
194
195    --  For the DIRECT_TRANSLATION case, an implicit additional entry is
196    --  created by prepending NO to the name of the qualifer, and then
197    --  inverting the sense of the UNIX_SWITCHES string. For example,
198    --  given the entry:
199
200    --     "/LIST -gnatl"
201
202    --  An implicit entry is created:
203
204    --     "/NOLIST !-gnatl"
205
206    --  In the case where, a ! is already present, inverting the sense of the
207    --  switch means removing it.
208
209    subtype S is String;
210    --  A synonym to shorten the table
211
212    type String_Ptr is access constant String;
213    --  String pointer type used throughout
214
215    type Switches is array (Natural range <>) of String_Ptr;
216    --  Type used for array of swtiches
217
218    type Switches_Ptr is access constant Switches;
219
220    --------------------------------
221    -- Switches for project files --
222    --------------------------------
223
224    S_Ext_Ref      : aliased constant S := "/EXTERNAL_REFERENCE=" & '"'    &
225                                             "-X" & '"';
226
227    S_Project_File : aliased constant S := "/PROJECT_FILE=<"               &
228                                             "-P>";
229    S_Project_Verb : aliased constant S := "/PROJECT_FILE_VERBOSITY="      &
230                                             "DEFAULT "                    &
231                                                "-vP0 "                    &
232                                             "MEDIUM "                     &
233                                                "-vP1 "                    &
234                                             "HIGH "                       &
235                                                "-vP2";
236
237    ----------------------------
238    -- Switches for GNAT BIND --
239    ----------------------------
240
241    S_Bind_Bind    : aliased constant S := "/BIND_FILE="                    &
242                                             "ADA "                         &
243                                                "-A "                       &
244                                             "C "                           &
245                                                "-C";
246
247    S_Bind_Build   : aliased constant S := "/BUILD_LIBRARY=|"               &
248                                             "-L|";
249
250    S_Bind_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
251                                             "!-I-";
252
253    S_Bind_Debug   : aliased constant S := "/DEBUG="                        &
254                                             "TRACEBACK "                   &
255                                                "-g2 "                      &
256                                             "ALL "                         &
257                                                "-g3 "                      &
258                                             "NONE "                        &
259                                                "-g0 "                      &
260                                             "SYMBOLS "                     &
261                                                "-g1 "                      &
262                                             "NOSYMBOLS "                   &
263                                                "!-g1 "                     &
264                                             "LINK "                        &
265                                                "-g3 "                      &
266                                             "NOTRACEBACK "                 &
267                                                "!-g2";
268
269    S_Bind_DebugX  : aliased constant S := "/NODEBUG "                      &
270                                             "!-g";
271
272    S_Bind_Elab    : aliased constant S := "/ELABORATION_DEPENDENCIES "     &
273                                             "-e";
274
275    S_Bind_Error   : aliased constant S := "/ERROR_LIMIT=#"                 &
276                                             "-m#";
277
278    S_Bind_Help    : aliased constant S := "/HELP "                         &
279                                             "-h";
280
281    S_Bind_Init    : aliased constant S := "/INITIALIZE_SCALARS="           &
282                                             "INVALID "                     &
283                                                "-Sin "                     &
284                                             "LOW "                         &
285                                                "-Slo "                     &
286                                             "HIGH "                        &
287                                                "-Shi";
288
289    S_Bind_Library : aliased constant S := "/LIBRARY_SEARCH=*"              &
290                                             "-aO*";
291
292    S_Bind_Linker  : aliased constant S := "/LINKER_OPTION_LIST "           &
293                                             "-K";
294
295    S_Bind_List    : aliased constant S := "/LIST_RESTRICTIONS "            &
296                                             "-r";
297
298    S_Bind_Main    : aliased constant S := "/MAIN "                         &
299                                             "!-n";
300
301    S_Bind_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
302                                             "-nostdinc";
303
304    S_Bind_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
305                                             "-nostdlib";
306
307    S_Bind_No_Time : aliased constant S := "/NO_TIME_STAMP_CHECK "          &
308                                             "-t";
309
310    S_Bind_Object  : aliased constant S := "/OBJECT_LIST "                  &
311                                             "-O";
312
313    S_Bind_Order   : aliased constant S := "/ORDER_OF_ELABORATION "         &
314                                             "-l";
315
316    S_Bind_Output  : aliased constant S := "/OUTPUT=@"                      &
317                                             "-o@";
318
319    S_Bind_OutputX : aliased constant S := "/NOOUTPUT "                     &
320                                             "-c";
321
322    S_Bind_Pess    : aliased constant S := "/PESSIMISTIC_ELABORATION "      &
323                                             "-p";
324
325    S_Bind_Read    : aliased constant S := "/READ_SOURCES="                 &
326                                             "ALL "                         &
327                                                "-s "                       &
328                                             "NONE "                        &
329                                                "-x "                       &
330                                             "AVAILABLE "                   &
331                                                "!-x,!-s";
332
333    S_Bind_ReadX   : aliased constant S := "/NOREAD_SOURCES "               &
334                                             "-x";
335
336    S_Bind_Rename  : aliased constant S := "/RENAME_MAIN=<"                  &
337                                             "-M>";
338
339    S_Bind_Report  : aliased constant S := "/REPORT_ERRORS="                &
340                                             "VERBOSE "                     &
341                                                "-v "                       &
342                                             "BRIEF "                       &
343                                                "-b "                       &
344                                             "DEFAULT "                     &
345                                                "!-b,!-v";
346
347    S_Bind_ReportX : aliased constant S := "/NOREPORT_ERRORS "              &
348                                             "!-b,!-v";
349
350    S_Bind_Restr   : aliased constant S := "/RESTRICTION_LIST "             &
351                                             "-r";
352
353    S_Bind_RTS     : aliased constant S := "/RUNTIME_SYSTEM=|"              &
354                                             "--RTS=|";
355
356    S_Bind_Search  : aliased constant S := "/SEARCH=*"                      &
357                                             "-I*";
358
359    S_Bind_Shared  : aliased constant S := "/SHARED "                       &
360                                             "-shared";
361
362    S_Bind_Slice   : aliased constant S := "/TIME_SLICE=#"                  &
363                                             "-T#";
364
365    S_Bind_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
366                                             "-aI*";
367
368    S_Bind_Time    : aliased constant S := "/TIME_STAMP_CHECK "             &
369                                             "!-t";
370
371    S_Bind_Verbose : aliased constant S := "/VERBOSE "                      &
372                                             "-v";
373
374    S_Bind_Warn    : aliased constant S := "/WARNINGS="                     &
375                                             "NORMAL "                      &
376                                                "!-ws,!-we "                &
377                                             "SUPPRESS "                    &
378                                                "-ws "                      &
379                                             "ERROR "                       &
380                                                "-we";
381
382    S_Bind_WarnX   : aliased constant S := "/NOWARNINGS "                   &
383      "-ws";
384
385    Bind_Switches : aliased constant Switches :=
386      (S_Bind_Bind    'Access,
387       S_Bind_Build   'Access,
388       S_Bind_Current 'Access,
389       S_Bind_Debug   'Access,
390       S_Bind_DebugX  'Access,
391       S_Bind_Elab    'Access,
392       S_Bind_Error   'Access,
393       S_Ext_Ref      'Access,
394       S_Bind_Help    'Access,
395       S_Bind_Init    'Access,
396       S_Bind_Library 'Access,
397       S_Bind_Linker  'Access,
398       S_Bind_List    'Access,
399       S_Bind_Main    'Access,
400       S_Bind_Nostinc 'Access,
401       S_Bind_Nostlib 'Access,
402       S_Bind_No_Time 'Access,
403       S_Bind_Object  'Access,
404       S_Bind_Order   'Access,
405       S_Bind_Output  'Access,
406       S_Bind_OutputX 'Access,
407       S_Bind_Pess    'Access,
408       S_Project_File 'Access,
409       S_Project_Verb 'Access,
410       S_Bind_Read    'Access,
411       S_Bind_ReadX   'Access,
412       S_Bind_Rename  'Access,
413       S_Bind_Report  'Access,
414       S_Bind_ReportX 'Access,
415       S_Bind_Restr   'Access,
416       S_Bind_RTS     'Access,
417       S_Bind_Search  'Access,
418       S_Bind_Shared  'Access,
419       S_Bind_Slice   'Access,
420       S_Bind_Source  'Access,
421       S_Bind_Time    'Access,
422       S_Bind_Verbose 'Access,
423       S_Bind_Warn    'Access,
424       S_Bind_WarnX   'Access);
425
426    ----------------------------
427    -- Switches for GNAT CHOP --
428    ----------------------------
429
430    S_Chop_Comp   : aliased constant S := "/COMPILATION "                   &
431                                             "-c";
432
433    S_Chop_File   : aliased constant S := "/FILE_NAME_MAX_LENGTH=#"         &
434                                             "-k#";
435
436    S_Chop_Help   : aliased constant S := "/HELP "                          &
437                                             "-h";
438
439    S_Chop_Over   : aliased constant S := "/OVERWRITE "                     &
440                                             "-w";
441
442    S_Chop_Pres   : aliased constant S := "/PRESERVE "                      &
443                                             "-p";
444
445    S_Chop_Quiet  : aliased constant S := "/QUIET "                         &
446                                             "-q";
447
448    S_Chop_Ref    : aliased constant S := "/REFERENCE "                     &
449                                             "-r";
450
451    S_Chop_Verb   : aliased constant S := "/VERBOSE "                       &
452                                             "-v";
453
454    Chop_Switches : aliased constant Switches :=
455      (S_Chop_Comp   'Access,
456       S_Chop_File   'Access,
457       S_Chop_Help   'Access,
458       S_Chop_Over   'Access,
459       S_Chop_Pres   'Access,
460       S_Chop_Quiet  'Access,
461       S_Chop_Ref    'Access,
462       S_Chop_Verb   'Access);
463
464    -------------------------------
465    -- Switches for GNAT COMPILE --
466    -------------------------------
467
468    S_GCC_Ada_83  : aliased constant S := "/83 "                            &
469                                              "-gnat83";
470
471    S_GCC_Ada_95  : aliased constant S := "/95 "                            &
472                                              "!-gnat83";
473
474    S_GCC_Asm     : aliased constant S := "/ASM "                           &
475                                              "-S,!-c";
476
477    S_GCC_Checks  : aliased constant S := "/CHECKS="                        &
478                                              "FULL "                       &
479                                                 "-gnato,!-gnatE,!-gnatp "  &
480                                              "OVERFLOW "                   &
481                                                 "-gnato "                  &
482                                              "ELABORATION "                &
483                                                 "-gnatE "                  &
484                                              "ASSERTIONS "                 &
485                                                 "-gnata "                  &
486                                              "DEFAULT "                    &
487                                                 "!-gnato,!-gnatp "         &
488                                              "SUPPRESS_ALL "               &
489                                                 "-gnatp";
490
491    S_GCC_ChecksX : aliased constant S := "/NOCHECKS "                      &
492                                              "-gnatp,!-gnato,!-gnatE";
493
494    S_GCC_Compres : aliased constant S := "/COMPRESS_NAMES "                &
495                                              "-gnatC";
496
497    S_GCC_Config  : aliased constant S := "/CONFIGURATION_PRAGMAS_FILE=<"   &
498                                              "-gnatec>";
499
500    S_GCC_Current : aliased constant S := "/CURRENT_DIRECTORY "             &
501                                              "!-I-";
502
503    S_GCC_Debug   : aliased constant S := "/DEBUG="                         &
504                                             "SYMBOLS "                     &
505                                                "-g2 "                      &
506                                             "NOSYMBOLS "                   &
507                                                "!-g2 "                     &
508                                             "TRACEBACK "                   &
509                                                "-g1 "                      &
510                                             "ALL "                         &
511                                                "-g3 "                      &
512                                             "NONE "                        &
513                                                "-g0 "                      &
514                                             "NOTRACEBACK "                 &
515                                                "-g0";
516
517    S_GCC_DebugX  : aliased constant S := "/NODEBUG "                       &
518                                              "!-g";
519
520    S_GCC_Dist    : aliased constant S := "/DISTRIBUTION_STUBS="            &
521                                             "RECEIVER "                    &
522                                                "-gnatzr "                  &
523                                             "CALLER "                      &
524                                               "-gnatzc";
525
526    S_GCC_DistX   : aliased constant S := "/NODISTRIBUTION_STUBS "          &
527                                             "!-gnatzr,!-gnatzc";
528
529    S_GCC_Error   : aliased constant S := "/ERROR_LIMIT=#"                  &
530                                             "-gnatm#";
531
532    S_GCC_ErrorX  : aliased constant S := "/NOERROR_LIMIT "                 &
533                                             "-gnatm999";
534
535    S_GCC_Expand  : aliased constant S := "/EXPAND_SOURCE "                 &
536                                             "-gnatG";
537
538    S_GCC_Extend  : aliased constant S := "/EXTENSIONS_ALLOWED "            &
539                                             "-gnatX";
540
541    S_GCC_File    : aliased constant S := "/FILE_NAME_MAX_LENGTH=#"         &
542                                             "-gnatk#";
543
544    S_GCC_Force   : aliased constant S := "/FORCE_ALI "                     &
545                                             "-gnatQ";
546
547    S_GCC_Help    : aliased constant S := "/HELP "                     &
548                                             "-gnath";
549
550    S_GCC_Ident   : aliased constant S := "/IDENTIFIER_CHARACTER_SET="      &
551                                              "DEFAULT "                    &
552                                                 "-gnati1 "                 &
553                                              "1 "                          &
554                                                 "-gnati1 "                 &
555                                              "2 "                          &
556                                                 "-gnati2 "                 &
557                                              "3 "                          &
558                                                 "-gnati3 "                 &
559                                              "4 "                          &
560                                                 "-gnati4 "                 &
561                                              "5 "                          &
562                                                 "-gnati5 "                 &
563                                              "PC "                         &
564                                                 "-gnatip "                 &
565                                              "PC850 "                      &
566                                                 "-gnati8 "                 &
567                                              "FULL_UPPER "                 &
568                                                 "-gnatif "                 &
569                                              "NO_UPPER "                   &
570                                                 "-gnatin "                 &
571                                              "WIDE "                       &
572                                                 "-gnatiw";
573
574    S_GCC_IdentX  : aliased constant S := "/NOIDENTIFIER_CHARACTER_SET "    &
575                                              "-gnati1";
576
577    S_GCC_Immed   : aliased constant S := "/IMMEDIATE_ERRORS "    &
578                                              "-gnatdO";
579
580    S_GCC_Inline  : aliased constant S := "/INLINE="                        &
581                                             "PRAGMA "                      &
582                                               "-gnatn "                    &
583                                             "FULL "                        &
584                                               "-gnatN "                    &
585                                             "SUPPRESS "                    &
586                                               "-fno-inline";
587
588    S_GCC_InlineX : aliased constant S := "/NOINLINE "                      &
589                                              "!-gnatn";
590
591    S_GCC_Jumps   : aliased constant S := "/LONGJMP_SETJMP "                &
592                                              "-gnatL";
593
594    S_GCC_Length  : aliased constant S := "/MAX_LINE_LENGTH=#"              &
595                                              "-gnatyM#";
596
597    S_GCC_List    : aliased constant S := "/LIST "                          &
598                                              "-gnatl";
599
600    S_GCC_Noadc   : aliased constant S := "/NO_GNAT_ADC "                   &
601                                              "-gnatA";
602
603    S_GCC_Noload  : aliased constant S := "/NOLOAD "                        &
604                                              "-gnatc";
605
606    S_GCC_Nostinc : aliased constant S := "/NOSTD_INCLUDES "                &
607                                              "-nostdinc";
608
609    S_GCC_Opt     : aliased constant S := "/OPTIMIZE="                      &
610                                             "ALL "                         &
611                                                "-O2,!-O0,!-O1,!-O3 "       &
612                                             "NONE "                        &
613                                                "-O0,!-O1,!-O2,!-O3 "       &
614                                             "SOME "                        &
615                                                "-O1,!-O0,!-O2,!-O3 "       &
616                                             "DEVELOPMENT "                 &
617                                                "-O1,!-O0,!-O2,!-O3 "       &
618                                             "UNROLL_LOOPS "                &
619                                                "-funroll-loops "           &
620                                             "INLINING "                    &
621                                                "-O3,!-O0,!-O1,!-O2";
622
623    S_GCC_OptX    : aliased constant S := "/NOOPTIMIZE "                    &
624                                             "-O0,!-O1,!-O2,!-O3";
625
626    S_GCC_Polling : aliased constant S := "/POLLING "                       &
627                                             "-gnatP";
628
629    S_GCC_Report  : aliased constant S := "/REPORT_ERRORS="                 &
630                                             "VERBOSE "                     &
631                                                "-gnatv "                   &
632                                             "BRIEF "                       &
633                                                "-gnatb "                   &
634                                             "FULL "                        &
635                                                "-gnatf "                   &
636                                             "IMMEDIATE "                   &
637                                                "-gnate "                   &
638                                             "DEFAULT "                     &
639                                                "!-gnatb,!-gnatv";
640
641    S_GCC_ReportX : aliased constant S := "/NOREPORT_ERRORS "               &
642                                             "!-gnatb,!-gnatv";
643
644    S_GCC_Repinfo : aliased constant S := "/REPRESENTATION_INFO="           &
645                                             "ARRAYS "                      &
646                                                "-gnatR1 "                  &
647                                             "NONE "                        &
648                                                "-gnatR0 "                  &
649                                             "OBJECTS "                     &
650                                                "-gnatR2 "                  &
651                                             "SYMBOLIC "                    &
652                                                "-gnatR3 "                  &
653                                             "DEFAULT "                     &
654                                                "-gnatR";
655
656    S_GCC_RepinfX : aliased constant S := "/NOREPRESENTATION_INFO "         &
657                                             "!-gnatR";
658
659    S_GCC_Search  : aliased constant S := "/SEARCH=*"                       &
660                                             "-I*";
661
662    S_GCC_Style   : aliased constant S := "/STYLE_CHECKS="                  &
663                                             "ALL_BUILTIN "                 &
664                                                "-gnaty "                   &
665                                             "1 "                           &
666                                                "-gnaty1 "                  &
667                                             "2 "                           &
668                                                "-gnaty2 "                  &
669                                             "3 "                           &
670                                                "-gnaty3 "                  &
671                                             "4 "                           &
672                                                "-gnaty4 "                  &
673                                             "5 "                           &
674                                                "-gnaty5 "                  &
675                                             "6 "                           &
676                                                "-gnaty6 "                  &
677                                             "7 "                           &
678                                                "-gnaty7 "                  &
679                                             "8 "                           &
680                                                "-gnaty8 "                  &
681                                             "9 "                           &
682                                                "-gnaty9 "                  &
683                                             "ATTRIBUTE "                   &
684                                                "-gnatya "                  &
685                                             "BLANKS "                      &
686                                                "-gnatyb "                  &
687                                             "COMMENTS "                    &
688                                                "-gnatyc "                  &
689                                             "END "                         &
690                                                "-gnatye "                  &
691                                             "VTABS "                       &
692                                                "-gnatyf "                  &
693                                             "GNAT "                        &
694                                                "-gnatg "                   &
695                                             "HTABS "                       &
696                                                "-gnatyh "                  &
697                                             "IF_THEN "                     &
698                                                "-gnatyi "                  &
699                                             "KEYWORD "                     &
700                                                "-gnatyk "                  &
701                                             "LAYOUT "                      &
702                                                "-gnatyl "                  &
703                                             "LINE_LENGTH "                 &
704                                                "-gnatym "                  &
705                                             "STANDARD_CASING "             &
706                                                "-gnatyn "                  &
707                                             "ORDERED_SUBPROGRAMS "         &
708                                                "-gnatyo "                  &
709                                             "NONE "                        &
710                                                "!-gnatg,!-gnatr "          &
711                                             "PRAGMA "                      &
712                                                "-gnatyp "                  &
713                                             "RM_COLUMN_LAYOUT "            &
714                                                "-gnatr "                   &
715                                             "SPECS "                       &
716                                                "-gnatys "                  &
717                                             "TOKEN "                       &
718                                                "-gnatyt ";
719
720    S_GCC_StyleX  : aliased constant S := "/NOSTYLE_CHECKS "                &
721                                             "!-gnatg,!-gnatr";
722
723    S_GCC_Syntax  : aliased constant S := "/SYNTAX_ONLY "                   &
724                                             "-gnats";
725
726    S_GCC_Trace   : aliased constant S := "/TRACE_UNITS "                   &
727                                             "-gnatdc";
728
729    S_GCC_Tree    : aliased constant S := "/TREE_OUTPUT "                   &
730                                             "-gnatt";
731
732    S_GCC_Trys    : aliased constant S := "/TRY_SEMANTICS "                 &
733                                             "-gnatq";
734
735    S_GCC_Units   : aliased constant S := "/UNITS_LIST "                    &
736                                             "-gnatu";
737
738    S_GCC_Unique  : aliased constant S := "/UNIQUE_ERROR_TAG "              &
739                                             "-gnatU";
740
741    S_GCC_Upcase  : aliased constant S := "/UPPERCASE_EXTERNALS "           &
742                                             "-gnatF";
743
744    S_GCC_Valid   : aliased constant S := "/VALIDITY_CHECKING="             &
745                                             "DEFAULT "                     &
746                                                "-gnatVd "                  &
747                                             "NODEFAULT "                   &
748                                                "-gnatVD "                  &
749                                             "COPIES "                      &
750                                                "-gnatVc "                  &
751                                             "NOCOPIES "                    &
752                                                "-gnatVC "                  &
753                                             "FLOATS "                      &
754                                                "-gnatVf "                  &
755                                             "NOFLOATS "                    &
756                                                "-gnatVF "                  &
757                                             "IN_PARAMS "                   &
758                                                "-gnatVi "                  &
759                                             "NOIN_PARAMS "                 &
760                                                "-gnatVI "                  &
761                                             "MOD_PARAMS "                  &
762                                                "-gnatVm "                  &
763                                             "NOMOD_PARAMS "                &
764                                                "-gnatVM "                  &
765                                             "OPERANDS "                    &
766                                                "-gnatVo "                  &
767                                             "NOOPERANDS "                  &
768                                                "-gnatVO "                  &
769                                             "RETURNS "                     &
770                                                "-gnatVr "                  &
771                                             "NORETURNS "                   &
772                                                "-gnatVR "                  &
773                                             "SUBSCRIPTS "                  &
774                                                "-gnatVs "                  &
775                                             "NOSUBSCRIPTS "                &
776                                                "-gnatVS "                  &
777                                             "TESTS "                       &
778                                                "-gnatVt "                  &
779                                             "NOTESTS "                     &
780                                                "-gnatVT "                  &
781                                             "ALL "                         &
782                                                "-gnatVa "                  &
783                                             "NONE "                        &
784                                                "-gnatVn";
785
786    S_GCC_Verbose : aliased constant S := "/VERBOSE "                       &
787                                             "-v";
788
789    S_GCC_Warn    : aliased constant S := "/WARNINGS="                      &
790                                             "DEFAULT "                     &
791                                                "!-gnatws,!-gnatwe "        &
792                                             "ALL_GCC "                     &
793                                                "-Wall "                    &
794                                             "BIASED_ROUNDING "             &
795                                                "-gnatwb "                  &
796                                             "NOBIASED_ROUNDING "           &
797                                                "-gnatwB "                  &
798                                             "CONDITIONALS "                &
799                                                "-gnatwc "                  &
800                                             "NOCONDITIONALS "              &
801                                                "-gnatwC "                  &
802                                             "IMPLICIT_DEREFERENCE "        &
803                                                "-gnatwd "                  &
804                                             "NO_IMPLICIT_DEREFERENCE "     &
805                                                "-gnatwD "                  &
806                                             "ELABORATION "                 &
807                                                "-gnatwl "                  &
808                                             "NOELABORATION "               &
809                                                "-gnatwL "                  &
810                                             "ERRORS "                      &
811                                                "-gnatwe "                  &
812                                             "HIDING "                      &
813                                                "-gnatwh "                  &
814                                             "NOHIDING "                    &
815                                                "-gnatwH "                  &
816                                             "IMPLEMENTATION "              &
817                                                "-gnatwi "                  &
818                                             "NOIMPLEMENTATION "            &
819                                                "-gnatwI "                  &
820                                             "INEFFECTIVE_INLINE "          &
821                                                "-gnatwp "                  &
822                                             "NOINEFFECTIVE_INLINE "        &
823                                                "-gnatwP "                  &
824                                             "OPTIONAL "                    &
825                                                "-gnatwa "                  &
826                                             "NOOPTIONAL "                  &
827                                                "-gnatwA "                  &
828                                             "OVERLAYS "                    &
829                                                "-gnatwo "                  &
830                                             "NOOVERLAYS "                  &
831                                                "-gnatwO "                  &
832                                             "REDUNDANT "                   &
833                                                "-gnatwr "                  &
834                                             "NOREDUNDANT "                 &
835                                                "-gnatwR "                  &
836                                             "SUPPRESS "                    &
837                                                "-gnatws "                  &
838                                             "UNINITIALIZED "               &
839                                                "-Wuninitialized "          &
840                                             "UNREFERENCED_FORMALS "        &
841                                                "-gnatwf "                  &
842                                             "NOUNREFERENCED_FORMALS "      &
843                                                "-gnatwF "                  &
844                                             "UNUSED "                      &
845                                                "-gnatwu "                  &
846                                             "NOUNUSED "                    &
847                                                "-gnatwU";
848
849    S_GCC_WarnX   : aliased constant S := "/NOWARNINGS "                    &
850                                             "-gnatws";
851
852    S_GCC_Wide    : aliased constant S := "/WIDE_CHARACTER_ENCODING="       &
853                                              "BRACKETS "                   &
854                                                 "-gnatWb "                 &
855                                              "NONE "                       &
856                                                 "-gnatWn "                 &
857                                              "HEX "                        &
858                                                 "-gnatWh "                 &
859                                              "UPPER "                      &
860                                                 "-gnatWu "                 &
861                                              "SHIFT_JIS "                  &
862                                                 "-gnatWs "                 &
863                                              "UTF8 "                       &
864                                                 "-gnatW8 "                 &
865                                              "EUC "                        &
866                                                 "-gnatWe";
867
868    S_GCC_WideX   : aliased constant S := "/NOWIDE_CHARACTER_ENCODING "     &
869                                              "-gnatWn";
870
871    S_GCC_Xdebug  : aliased constant S := "/XDEBUG "                        &
872                                              "-gnatD";
873
874    S_GCC_Xref    : aliased constant S := "/XREF="                          &
875                                             "GENERATE "                    &
876                                                "!-gnatx "                  &
877                                             "SUPPRESS "                    &
878                                                "-gnatx";
879
880    GCC_Switches : aliased constant Switches :=
881      (S_GCC_Ada_83  'Access,
882       S_GCC_Ada_95  'Access,
883       S_GCC_Asm     'Access,
884       S_GCC_Checks  'Access,
885       S_GCC_ChecksX 'Access,
886       S_GCC_Compres 'Access,
887       S_GCC_Config  'Access,
888       S_GCC_Current 'Access,
889       S_GCC_Debug   'Access,
890       S_GCC_DebugX  'Access,
891       S_GCC_Dist    'Access,
892       S_GCC_DistX   'Access,
893       S_GCC_Error   'Access,
894       S_GCC_ErrorX  'Access,
895       S_GCC_Expand  'Access,
896       S_GCC_Extend  'Access,
897       S_Ext_Ref     'Access,
898       S_GCC_File    'Access,
899       S_GCC_Force   'Access,
900       S_GCC_Help    'Access,
901       S_GCC_Ident   'Access,
902       S_GCC_IdentX  'Access,
903       S_GCC_Immed   'Access,
904       S_GCC_Inline  'Access,
905       S_GCC_InlineX 'Access,
906       S_GCC_Jumps   'Access,
907       S_GCC_Length  'Access,
908       S_GCC_List    'Access,
909       S_GCC_Noadc   'Access,
910       S_GCC_Noload  'Access,
911       S_GCC_Nostinc 'Access,
912       S_GCC_Opt     'Access,
913       S_GCC_OptX    'Access,
914       S_GCC_Polling 'Access,
915       S_Project_File'Access,
916       S_Project_Verb'Access,
917       S_GCC_Report  'Access,
918       S_GCC_ReportX 'Access,
919       S_GCC_Repinfo 'Access,
920       S_GCC_RepinfX 'Access,
921       S_GCC_Search  'Access,
922       S_GCC_Style   'Access,
923       S_GCC_StyleX  'Access,
924       S_GCC_Syntax  'Access,
925       S_GCC_Trace   'Access,
926       S_GCC_Tree    'Access,
927       S_GCC_Trys    'Access,
928       S_GCC_Units   'Access,
929       S_GCC_Unique  'Access,
930       S_GCC_Upcase  'Access,
931       S_GCC_Valid   'Access,
932       S_GCC_Verbose 'Access,
933       S_GCC_Warn    'Access,
934       S_GCC_WarnX   'Access,
935       S_GCC_Wide    'Access,
936       S_GCC_WideX   'Access,
937       S_GCC_Xdebug  'Access,
938       S_GCC_Xref    'Access);
939
940    ----------------------------
941    -- Switches for GNAT ELIM --
942    ----------------------------
943
944    S_Elim_All    : aliased constant S := "/ALL "                           &
945                                             "-a";
946
947    S_Elim_Bind   : aliased constant S := "/BIND_FILE=<"                    &
948                                             "-b>";
949
950    S_Elim_Miss   : aliased constant S := "/MISSED "                        &
951                                             "-m";
952
953    S_Elim_Quiet  : aliased constant S := "/QUIET "                         &
954                                             "-q";
955
956    S_Elim_Tree   : aliased constant S := "/TREE_DIRS=*"                    &
957                                             "-T*";
958
959    S_Elim_Verb   : aliased constant S := "/VERBOSE "                       &
960                                             "-v";
961
962    Elim_Switches : aliased constant Switches :=
963      (S_Elim_All    'Access,
964       S_Elim_Bind   'Access,
965       S_Elim_Miss   'Access,
966       S_Elim_Quiet  'Access,
967       S_Elim_Tree   'Access,
968       S_Elim_Verb   'Access);
969
970    ----------------------------
971    -- Switches for GNAT FIND --
972    ----------------------------
973
974    S_Find_All     : aliased constant S := "/ALL_FILES "                    &
975                                             "-a";
976
977    S_Find_Deriv   : aliased constant S := "/DERIVED_TYPE_INFORMATION "     &
978                                             "-d";
979
980    S_Find_Expr    : aliased constant S := "/EXPRESSIONS "                  &
981                                             "-e";
982
983    S_Find_Full    : aliased constant S := "/FULL_PATHNAME "                &
984                                             "-f";
985
986    S_Find_Ignore  : aliased constant S := "/IGNORE_LOCALS "                &
987                                             "-g";
988
989    S_Find_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
990                                             "-nostdinc";
991
992    S_Find_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
993                                             "-nostdlib";
994
995    S_Find_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
996                                             "-aO*";
997
998    S_Find_Print   : aliased constant S := "/PRINT_LINES "                  &
999                                             "-s";
1000
1001    S_Find_Project : aliased constant S := "/PROJECT=@"                     &
1002                                             "-p@";
1003
1004    S_Find_Ref     : aliased constant S := "/REFERENCES "                   &
1005                                             "-r";
1006
1007    S_Find_Search  : aliased constant S := "/SEARCH=*"                      &
1008                                             "-I*";
1009
1010    S_Find_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
1011                                             "-aI*";
1012
1013    S_Find_Types   : aliased constant S := "/TYPE_HIERARCHY "               &
1014                                             "-t";
1015
1016    Find_Switches : aliased constant Switches :=
1017      (S_Find_All     'Access,
1018       S_Find_Deriv   'Access,
1019       S_Find_Expr    'Access,
1020       S_Ext_Ref      'Access,
1021       S_Find_Full    'Access,
1022       S_Find_Ignore  'Access,
1023       S_Find_Nostinc 'Access,
1024       S_Find_Nostlib 'Access,
1025       S_Find_Object  'Access,
1026       S_Find_Print   'Access,
1027       S_Find_Project 'Access,
1028       S_Project_File 'Access,
1029       S_Project_Verb 'Access,
1030       S_Find_Ref     'Access,
1031       S_Find_Search  'Access,
1032       S_Find_Source  'Access,
1033       S_Find_Types   'Access);
1034
1035    ------------------------------
1036    -- Switches for GNAT KRUNCH --
1037    ------------------------------
1038
1039    S_Krunch_Count  : aliased constant S := "/COUNT=#"                      &
1040                                             "`#";
1041
1042    Krunch_Switches : aliased constant Switches  :=
1043      (1 .. 1 => S_Krunch_Count  'Access);
1044
1045    -------------------------------
1046    -- Switches for GNAT LIBRARY --
1047    -------------------------------
1048
1049    S_Lbr_Config    : aliased constant S := "/CONFIG=@"                     &
1050                                             "--config=@";
1051
1052    S_Lbr_Create    : aliased constant S := "/CREATE=%"                     &
1053                                             "--create=%";
1054
1055    S_Lbr_Delete    : aliased constant S := "/DELETE=%"                     &
1056                                             "--delete=%";
1057
1058    S_Lbr_Set       : aliased constant S := "/SET=%"                        &
1059                                             "--set=%";
1060
1061    Lbr_Switches : aliased constant Switches  :=
1062      (S_Lbr_Config 'Access,
1063       S_Lbr_Create 'Access,
1064       S_Lbr_Delete 'Access,
1065       S_Lbr_Set    'Access);
1066
1067    ----------------------------
1068    -- Switches for GNAT LINK --
1069    ----------------------------
1070
1071    S_Link_Bind    : aliased constant S := "/BIND_FILE="                    &
1072                                             "ADA "                         &
1073                                                "-A "                       &
1074                                             "C "                           &
1075                                                "-C";
1076
1077    S_Link_Debug   : aliased constant S := "/DEBUG="                        &
1078                                             "ALL "                         &
1079                                                "-g3 "                      &
1080                                             "NONE "                        &
1081                                                "-g0 "                      &
1082                                             "TRACEBACK "                   &
1083                                                "-g1 "                      &
1084                                             "NOTRACEBACK "                 &
1085                                                "-g0";
1086
1087    S_Link_Execut  : aliased constant S := "/EXECUTABLE=@"                  &
1088                                             "-o@";
1089
1090    S_Link_Force   : aliased constant S := "/FORCE_OBJECT_FILE_LIST "       &
1091                                             "-f";
1092
1093    S_Link_Ident   : aliased constant S := "/IDENTIFICATION=" & '"'         &
1094                                             "--for-linker=IDENT="          &
1095                                             '"';
1096
1097    S_Link_Nocomp  : aliased constant S := "/NOCOMPILE "                    &
1098                                             "-n";
1099
1100    S_Link_Nofiles : aliased constant S := "/NOSTART_FILES "                &
1101                                             "-nostartfiles";
1102
1103    S_Link_Noinhib : aliased constant S := "/NOINHIBIT-EXEC "               &
1104                                             "--for-linker=--noinhibit-exec";
1105
1106    S_Link_Static  : aliased constant S := "/STATIC "                       &
1107                                             "--for-linker=-static";
1108
1109    S_Link_Verb    : aliased constant S := "/VERBOSE "                      &
1110                                             "-v";
1111
1112    S_Link_ZZZZZ   : aliased constant S := "/<other> "                      &
1113                                             "--for-linker=";
1114
1115    Link_Switches : aliased constant Switches :=
1116      (S_Link_Bind    'Access,
1117       S_Link_Debug   'Access,
1118       S_Link_Execut  'Access,
1119       S_Ext_Ref      'Access,
1120       S_Link_Force   'Access,
1121       S_Link_Ident   'Access,
1122       S_Link_Nocomp  'Access,
1123       S_Link_Nofiles 'Access,
1124       S_Link_Noinhib 'Access,
1125       S_Project_File 'Access,
1126       S_Project_Verb 'Access,
1127       S_Link_Static  'Access,
1128       S_Link_Verb    'Access,
1129       S_Link_ZZZZZ   'Access);
1130
1131    ----------------------------
1132    -- Switches for GNAT LIST --
1133    ----------------------------
1134
1135    S_List_All     : aliased constant S := "/ALL_UNITS "                    &
1136                                             "-a";
1137
1138    S_List_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
1139                                             "!-I-";
1140
1141    S_List_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
1142                                             "-nostdinc";
1143
1144    S_List_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
1145                                             "-aO*";
1146
1147    S_List_Output  : aliased constant S := "/OUTPUT="                       &
1148                                             "SOURCES "                     &
1149                                                "-s "                       &
1150                                             "DEPEND "                      &
1151                                                "-d "                       &
1152                                             "OBJECTS "                     &
1153                                                "-o "                       &
1154                                             "UNITS "                       &
1155                                                "-u "                       &
1156                                             "OPTIONS "                     &
1157                                                "-h "                       &
1158                                             "VERBOSE "                     &
1159                                                "-v ";
1160
1161    S_List_Search  : aliased constant S := "/SEARCH=*"                      &
1162                                             "-I*";
1163
1164    S_List_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
1165                                             "-aI*";
1166
1167    List_Switches : aliased constant Switches :=
1168      (S_List_All     'Access,
1169       S_List_Current 'Access,
1170       S_Ext_Ref      'Access,
1171       S_List_Nostinc 'Access,
1172       S_List_Object  'Access,
1173       S_List_Output  'Access,
1174       S_Project_File 'Access,
1175       S_Project_Verb 'Access,
1176       S_List_Search  'Access,
1177       S_List_Source  'Access);
1178
1179    ----------------------------
1180    -- Switches for GNAT MAKE --
1181    ----------------------------
1182
1183    S_Make_Actions : aliased constant S := "/ACTIONS="                      &
1184                                             "COMPILE "                     &
1185                                                "-c "                       &
1186                                             "BIND "                        &
1187                                                "-b "                       &
1188                                             "LINK "                        &
1189                                                "-l ";
1190
1191    S_Make_All     : aliased constant S := "/ALL_FILES "                    &
1192                                             "-a";
1193
1194    S_Make_Bind    : aliased constant S := "/BINDER_QUALIFIERS=?"           &
1195                                             "-bargs BIND";
1196
1197    S_Make_Comp    : aliased constant S := "/COMPILER_QUALIFIERS=?"         &
1198                                             "-cargs COMPILE";
1199
1200    S_Make_Cond    : aliased constant S := "/CONDITIONAL_SOURCE_SEARCH=*"   &
1201                                             "-A*";
1202
1203    S_Make_Cont    : aliased constant S := "/CONTINUE_ON_ERROR "            &
1204                                             "-k";
1205
1206    S_Make_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
1207                                             "!-I-";
1208
1209    S_Make_Dep     : aliased constant S := "/DEPENDENCIES_LIST "            &
1210                                             "-M";
1211
1212    S_Make_Doobj   : aliased constant S := "/DO_OBJECT_CHECK "              &
1213                                             "-n";
1214
1215    S_Make_Execut  : aliased constant S := "/EXECUTABLE=@"                  &
1216                                             "-o@";
1217
1218    S_Make_Force   : aliased constant S := "/FORCE_COMPILE "                &
1219                                             "-f";
1220
1221    S_Make_Inplace : aliased constant S := "/IN_PLACE "                     &
1222                                             "-i";
1223
1224    S_Make_Library : aliased constant S := "/LIBRARY_SEARCH=*"              &
1225                                             "-L*";
1226
1227    S_Make_Link    : aliased constant S := "/LINKER_QUALIFIERS=?"           &
1228                                             "-largs LINK";
1229
1230    S_Make_Mapping : aliased constant S := "/MAPPING "                      &
1231                                             "-C";
1232
1233    S_Make_Minimal : aliased constant S := "/MINIMAL_RECOMPILATION "        &
1234                                             "-m";
1235
1236    S_Make_Nolink  : aliased constant S := "/NOLINK "                       &
1237                                             "-c";
1238
1239    S_Make_Nomain  : aliased constant S := "/NOMAIN "                       &
1240                                             "-z";
1241
1242    S_Make_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
1243                                             "-nostdinc";
1244
1245    S_Make_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
1246                                             "-nostdlib";
1247
1248    S_Make_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
1249                                             "-aO*";
1250
1251    S_Make_Proc    : aliased constant S := "/PROCESSES=#"                   &
1252                                             "-j#";
1253
1254    S_Make_Nojobs  : aliased constant S := "/NOPROCESSES "                  &
1255                                             "-j1";
1256
1257    S_Make_Quiet   : aliased constant S := "/QUIET "                        &
1258                                             "-q";
1259
1260    S_Make_Reason  : aliased constant S := "/REASONS "                      &
1261                                             "-v";
1262
1263    S_Make_RTS     : aliased constant S := "/RUNTIME_SYSTEM=|"              &
1264                                             "--RTS=|";
1265
1266    S_Make_Search  : aliased constant S := "/SEARCH=*"                      &
1267                                             "-I*";
1268
1269    S_Make_Skip    : aliased constant S := "/SKIP_MISSING=*"                &
1270                                             "-aL*";
1271
1272    S_Make_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
1273                                             "-aI*";
1274
1275    S_Make_Switch  : aliased constant S := "/SWITCH_CHECK "               &
1276                                             "-s";
1277
1278    S_Make_Unique  : aliased constant S := "/UNIQUE "                       &
1279                                             "-u";
1280
1281    S_Make_Verbose : aliased constant S := "/VERBOSE "                      &
1282                                             "-v";
1283
1284    Make_Switches : aliased constant Switches :=
1285      (S_Make_Actions 'Access,
1286       S_Make_All     'Access,
1287       S_Make_Bind    'Access,
1288       S_Make_Comp    'Access,
1289       S_Make_Cond    'Access,
1290       S_Make_Cont    'Access,
1291       S_Make_Current 'Access,
1292       S_Make_Dep     'Access,
1293       S_Make_Doobj   'Access,
1294       S_Make_Execut  'Access,
1295       S_Ext_Ref      'Access,
1296       S_Make_Force   'Access,
1297       S_Make_Inplace 'Access,
1298       S_Make_Library 'Access,
1299       S_Make_Link    'Access,
1300       S_Make_Mapping 'Access,
1301       S_Make_Minimal 'Access,
1302       S_Make_Nolink  'Access,
1303       S_Make_Nomain  'Access,
1304       S_Make_Nostinc 'Access,
1305       S_Make_Nostlib 'Access,
1306       S_Make_Object  'Access,
1307       S_Make_Proc    'Access,
1308       S_Project_File 'Access,
1309       S_Project_Verb 'Access,
1310       S_Make_Nojobs  'Access,
1311       S_Make_Quiet   'Access,
1312       S_Make_Reason  'Access,
1313       S_Make_RTS     'Access,
1314       S_Make_Search  'Access,
1315       S_Make_Skip    'Access,
1316       S_Make_Source  'Access,
1317       S_Make_Switch  'Access,
1318       S_Make_Unique  'Access,
1319       S_Make_Verbose 'Access);
1320
1321    ----------------------------
1322    -- Switches for GNAT Name --
1323    ----------------------------
1324
1325    S_Name_Conf    : aliased constant S := "/CONFIG_FILE=<"                   &
1326                                             "-c>";
1327
1328    S_Name_Dirs    : aliased constant S := "/SOURCE_DIRS=*"                   &
1329                                             "-d*";
1330
1331    S_Name_Dfile   : aliased constant S := "/DIRS_FILE=<"                     &
1332                                             "-D>";
1333
1334    S_Name_Help    : aliased constant S := "/HELP"                            &
1335                                             " -h";
1336
1337    S_Name_Proj    : aliased constant S := "/PROJECT_FILE=<"                  &
1338                                             "-P>";
1339
1340    S_Name_Verbose : aliased constant S := "/VERBOSE"                         &
1341                                             " -v";
1342
1343    Name_Switches : aliased constant Switches :=
1344      (S_Name_Conf         'Access,
1345       S_Name_Dirs         'Access,
1346       S_Name_Dfile        'Access,
1347       S_Name_Help         'Access,
1348       S_Name_Proj         'Access,
1349       S_Name_Verbose      'Access);
1350
1351    ----------------------------------
1352    -- Switches for GNAT PREPROCESS --
1353    ----------------------------------
1354
1355    S_Prep_Assoc   : aliased constant S := "/ASSOCIATE=" & '"'               &
1356                                             "-D" & '"';
1357
1358    S_Prep_Blank   : aliased constant S := "/BLANK_LINES "                   &
1359                                             "-b";
1360
1361    S_Prep_Com     : aliased constant S := "/COMMENTS "                      &
1362                                             "-c";
1363
1364    S_Prep_Ref     : aliased constant S := "/REFERENCE "                     &
1365                                             "-r";
1366
1367    S_Prep_Remove  : aliased constant S := "/REMOVE "                        &
1368                                             "!-b,!-c";
1369
1370    S_Prep_Symbols : aliased constant S := "/SYMBOLS "                       &
1371                                             "-s";
1372
1373    S_Prep_Undef   : aliased constant S := "/UNDEFINED "                     &
1374                                             "-u";
1375
1376    Prep_Switches : aliased constant Switches :=
1377      (S_Prep_Assoc   'Access,
1378       S_Prep_Blank   'Access,
1379       S_Prep_Com     'Access,
1380       S_Prep_Ref     'Access,
1381       S_Prep_Remove  'Access,
1382       S_Prep_Symbols 'Access,
1383       S_Prep_Undef   'Access);
1384
1385    ------------------------------
1386    -- Switches for GNAT SHARED --
1387    ------------------------------
1388
1389    S_Shared_Debug   : aliased constant S := "/DEBUG="                      &
1390                                             "ALL "                         &
1391                                                "-g3 "                      &
1392                                             "NONE "                        &
1393                                                "-g0 "                      &
1394                                             "TRACEBACK "                   &
1395                                                "-g1 "                      &
1396                                             "NOTRACEBACK "                 &
1397                                                "-g0";
1398
1399    S_Shared_Image  : aliased constant S := "/IMAGE=@"                      &
1400                                             "-o@";
1401
1402    S_Shared_Ident   : aliased constant S := "/IDENTIFICATION=" & '"'       &
1403                                             "--for-linker=IDENT="          &
1404                                             '"';
1405
1406    S_Shared_Nofiles : aliased constant S := "/NOSTART_FILES "              &
1407                                             "-nostartfiles";
1408
1409    S_Shared_Noinhib : aliased constant S := "/NOINHIBIT-IMAGE "            &
1410                                             "--for-linker=--noinhibit-exec";
1411
1412    S_Shared_Verb    : aliased constant S := "/VERBOSE "                    &
1413                                             "-v";
1414
1415    S_Shared_ZZZZZ   : aliased constant S := "/<other> "                    &
1416                                             "--for-linker=";
1417
1418    Shared_Switches : aliased constant Switches :=
1419      (S_Shared_Debug   'Access,
1420       S_Shared_Image   'Access,
1421       S_Shared_Ident   'Access,
1422       S_Shared_Nofiles 'Access,
1423       S_Shared_Noinhib 'Access,
1424       S_Shared_Verb    'Access,
1425       S_Shared_ZZZZZ   'Access);
1426
1427    --------------------------------
1428    -- Switches for GNAT STANDARD --
1429    --------------------------------
1430
1431    Standard_Switches : aliased constant Switches := (1 .. 0 => null);
1432
1433    ----------------------------
1434    -- Switches for GNAT STUB --
1435    ----------------------------
1436
1437    S_Stub_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
1438                                             "!-I-";
1439
1440    S_Stub_Full    : aliased constant S := "/FULL "                         &
1441                                             "-f";
1442
1443    S_Stub_Header  : aliased constant S := "/HEADER="                       &
1444                                             "GENERAL "                     &
1445                                                "-hg "                      &
1446                                             "SPEC "                        &
1447                                                "-hs";
1448
1449    S_Stub_Indent  : aliased constant S := "/INDENTATION=#"                 &
1450                                             "-i#";
1451
1452    S_Stub_Length  : aliased constant S := "/LINE_LENGTH=#"                 &
1453                                             "-l#";
1454
1455    S_Stub_Quiet   : aliased constant S := "/QUIET "                        &
1456                                             "-q";
1457
1458    S_Stub_Search  : aliased constant S := "/SEARCH=*"                      &
1459                                             "-I*";
1460
1461    S_Stub_Tree    : aliased constant S := "/TREE_FILE="                    &
1462                                             "OVERWRITE "                   &
1463                                                "-t "                       &
1464                                             "SAVE "                        &
1465                                                "-k "                       &
1466                                             "REUSE "                       &
1467                                                "-r";
1468
1469    S_Stub_Verbose : aliased constant S := "/VERBOSE "                      &
1470                                             "-v";
1471
1472    Stub_Switches : aliased constant Switches :=
1473      (S_Stub_Current 'Access,
1474       S_Stub_Full    'Access,
1475       S_Stub_Header  'Access,
1476       S_Stub_Indent  'Access,
1477       S_Stub_Length  'Access,
1478       S_Stub_Quiet   'Access,
1479       S_Stub_Search  'Access,
1480       S_Stub_Tree    'Access,
1481       S_Stub_Verbose 'Access);
1482
1483    ----------------------------
1484    -- Switches for GNAT XREF --
1485    ----------------------------
1486
1487    S_Xref_All     : aliased constant S := "/ALL_FILES "                    &
1488                                             "-a";
1489
1490    S_Xref_Deriv   : aliased constant S := "/DERIVED_TYPES "                &
1491                                             "-d";
1492
1493    S_Xref_Full    : aliased constant S := "/FULL_PATHNAME "                &
1494                                             "-f";
1495
1496    S_Xref_Global  : aliased constant S := "/IGNORE_LOCALS "                &
1497                                             "-g";
1498
1499    S_Xref_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
1500                                             "-nostdinc";
1501
1502    S_Xref_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
1503                                             "-nostdlib";
1504
1505    S_Xref_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
1506                                             "-aO*";
1507
1508    S_Xref_Project : aliased constant S := "/PROJECT=@"                     &
1509                                             "-p@";
1510
1511    S_Xref_Search  : aliased constant S := "/SEARCH=*"                      &
1512                                             "-I*";
1513
1514    S_Xref_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
1515                                             "-aI*";
1516
1517    S_Xref_Output  : aliased constant S := "/UNUSED "                       &
1518                                             "-u";
1519
1520    S_Xref_Tags    : aliased constant S := "/TAGS "                         &
1521                                             "-v";
1522
1523    Xref_Switches : aliased constant Switches :=
1524      (S_Xref_All     'Access,
1525       S_Xref_Deriv   'Access,
1526       S_Ext_Ref      'Access,
1527       S_Xref_Full    'Access,
1528       S_Xref_Global  'Access,
1529       S_Xref_Nostinc 'Access,
1530       S_Xref_Nostlib 'Access,
1531       S_Xref_Object  'Access,
1532       S_Xref_Project 'Access,
1533       S_Project_File 'Access,
1534       S_Project_Verb 'Access,
1535       S_Xref_Search  'Access,
1536       S_Xref_Source  'Access,
1537       S_Xref_Output  'Access,
1538       S_Xref_Tags    'Access);
1539
1540    -------------------
1541    -- COMMAND TABLE --
1542    -------------------
1543
1544    --  The command table contains an entry for each command recognized by
1545    --  GNATCmd. The entries are represented by an array of records.
1546
1547    type Parameter_Type is
1548    --  A parameter is defined as a whitespace bounded string, not begining
1549    --   with a slash. (But see note under FILES_OR_WILDCARD).
1550      (File,
1551       --  A required file or directory parameter.
1552
1553       Optional_File,
1554       --  An optional file or directory parameter.
1555
1556       Other_As_Is,
1557       --  A parameter that's passed through as is (not canonicalized)
1558
1559       Unlimited_Files,
1560       --  An unlimited number of whitespace separate file or directory
1561       --  parameters including wildcard specifications.
1562
1563       Unlimited_As_Is,
1564       --  Un unlimited number of whitespace separated paameters that are
1565       --  passed through as is (not canonicalized).
1566
1567       Files_Or_Wildcard);
1568       --  A comma separated list of files and/or wildcard file specifications.
1569       --  A comma preceded by or followed by whitespace is considered as a
1570       --  single comma character w/o whitespace.
1571
1572    type Parameter_Array is array (Natural range <>) of Parameter_Type;
1573    type Parameter_Ref is access all Parameter_Array;
1574
1575    type Command_Type is
1576      (Bind, Chop, Compile, Elim, Find, Krunch, Library, Link, List,
1577       Make, Name, Preprocess, Shared, Standard, Stub, Xref, Undefined);
1578
1579    type Alternate_Command is (Comp, Ls, Kr, Prep, Psta);
1580    --  Alternate command libel for non VMS system
1581
1582    Corresponding_To : constant array (Alternate_Command) of Command_Type :=
1583      (Comp  => Compile,
1584       Ls    => List,
1585       Kr    => Krunch,
1586       Prep  => Preprocess,
1587       Psta  => Standard);
1588    --  Mapping of alternate commands to commands
1589
1590    subtype Real_Command_Type is Command_Type range Bind .. Xref;
1591
1592    type Command_Entry is record
1593       Cname : String_Ptr;
1594       --  Command name for GNAT xxx command
1595
1596       Usage : String_Ptr;
1597       --  A usage string, used for error messages
1598
1599       Unixcmd : String_Ptr;
1600       --  Corresponding Unix command
1601
1602       Unixsws : Argument_List_Access;
1603       --  Switches for the Unix command
1604
1605       VMS_Only : Boolean;
1606       --  When True, the command can only be used on VMS
1607
1608       Switches : Switches_Ptr;
1609       --  Pointer to array of switch strings
1610
1611       Params : Parameter_Ref;
1612       --  Describes the allowable types of parameters.
1613       --  Params (1) is the type of the first parameter, etc.
1614       --  An empty parameter array means this command takes no parameters.
1615
1616       Defext : String (1 .. 3);
1617       --  Default extension. If non-blank, then this extension is supplied by
1618       --  default as the extension for any file parameter which does not have
1619       --  an extension already.
1620    end record;
1621
1622    -------------------------
1623    -- INTERNAL STRUCTURES --
1624    -------------------------
1625
1626    --  The switches and commands are defined by strings in the previous
1627    --  section so that they are easy to modify, but internally, they are
1628    --  kept in a more conveniently accessible form described in this
1629    --  section.
1630
1631    --  Commands, command qualifers and options have a similar common format
1632    --  so that searching for matching names can be done in a common manner.
1633
1634    type Item_Id is (Id_Command, Id_Switch, Id_Option);
1635
1636    type Translation_Type is
1637      (
1638       T_Direct,
1639       --  A qualifier with no options.
1640       --  Example: GNAT MAKE /VERBOSE
1641
1642       T_Directories,
1643       --  A qualifier followed by a list of directories
1644       --  Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
1645
1646       T_Directory,
1647       --  A qualifier followed by one directory
1648       --  Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
1649
1650       T_File,
1651       --  A qualifier followed by a filename
1652       --  Example: GNAT LINK /EXECUTABLE=FOO.EXE
1653
1654       T_No_Space_File,
1655       --  A qualifier followed by a filename
1656       --  Example: GNAT MAKE /PROJECT_FILE=PRJ.GPR
1657
1658       T_Numeric,
1659       --  A qualifier followed by a numeric value.
1660       --  Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
1661
1662       T_String,
1663       --  A qualifier followed by a quoted string. Only used by
1664       --  /IDENTIFICATION qualfier.
1665       --  Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
1666
1667       T_Options,
1668       --  A qualifier followed by a list of options.
1669       --  Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
1670
1671       T_Commands,
1672       --  A qualifier followed by a list. Only used for
1673       --  MAKE /COMPILER_QUALIFIERS /BINDER_QUALIFIERS /LINKER_QUALIFIERS
1674       --  (gnatmake -cargs -bargs -largs )
1675       --  Example: GNAT MAKE ... /LINKER_QUALIFIERS /VERBOSE FOOBAR.OBJ
1676
1677       T_Other,
1678       --  A qualifier passed directly to the linker. Only used
1679       --  for LINK and SHARED if no other match is found.
1680       --  Example: GNAT LINK FOO.ALI /SYSSHR
1681
1682       T_Alphanumplus
1683       --  A qualifier followed by a legal linker symbol prefix. Only used
1684       --  for BIND /BUILD_LIBRARY (gnatbind -Lxyz).
1685       --  Example: GNAT BIND /BUILD_LIBRARY=foobar
1686       );
1687
1688    type Item (Id : Item_Id);
1689    type Item_Ptr is access all Item;
1690
1691    type Item (Id : Item_Id) is record
1692       Name : String_Ptr;
1693       --  Name of the command, switch (with slash) or option
1694
1695       Next : Item_Ptr;
1696       --  Pointer to next item on list, always has the same Id value
1697
1698       Command : Command_Type := Undefined;
1699
1700       Unix_String : String_Ptr := null;
1701       --  Corresponding Unix string. For a command, this is the unix command
1702       --  name and possible default switches. For a switch or option it is
1703       --  the unix switch string.
1704
1705       case Id is
1706
1707          when Id_Command =>
1708
1709             Switches : Item_Ptr;
1710             --  Pointer to list of switch items for the command, linked
1711             --  through the Next fields with null terminating the list.
1712
1713             Usage : String_Ptr;
1714             --  Usage information, used only for errors and the default
1715             --  list of commands output.
1716
1717             Params : Parameter_Ref;
1718             --  Array of parameters
1719
1720             Defext : String (1 .. 3);
1721             --  Default extension. If non-blank, then this extension is
1722             --  supplied by default as the extension for any file parameter
1723             --  which does not have an extension already.
1724
1725          when Id_Switch =>
1726
1727             Translation : Translation_Type;
1728             --  Type of switch translation. For all cases, except Options,
1729             --  this is the only field needed, since the Unix translation
1730             --  is found in Unix_String.
1731
1732             Options : Item_Ptr;
1733             --  For the Options case, this field is set to point to a list
1734             --  of options item (for this case Unix_String is null in the
1735             --  main switch item). The end of the list is marked by null.
1736
1737          when Id_Option =>
1738
1739             null;
1740             --  No special fields needed, since Name and Unix_String are
1741             --  sufficient to completely described an option.
1742
1743       end case;
1744    end record;
1745
1746    subtype Command_Item is Item (Id_Command);
1747    subtype Switch_Item  is Item (Id_Switch);
1748    subtype Option_Item  is Item (Id_Option);
1749
1750    ----------------------------------
1751    -- Declarations for GNATCMD use --
1752    ----------------------------------
1753
1754    Commands : Item_Ptr;
1755    --  Pointer to head of list of command items, one for each command, with
1756    --  the end of the list marked by a null pointer.
1757
1758    Last_Command : Item_Ptr;
1759    --  Pointer to last item in Commands list
1760
1761    Normal_Exit : exception;
1762    --  Raise this exception for normal program termination
1763
1764    Error_Exit : exception;
1765    --  Raise this exception if error detected
1766
1767    Errors : Natural := 0;
1768    --  Count errors detected
1769
1770    Command_Arg : Positive := 1;
1771
1772    Command : Item_Ptr;
1773    --  Pointer to command item for current command
1774
1775    Make_Commands_Active : Item_Ptr := null;
1776    --  Set to point to Command entry for COMPILE, BIND, or LINK as appropriate
1777    --  if a COMMANDS_TRANSLATION switch has been encountered while processing
1778    --  a MAKE Command.
1779
1780    My_Exit_Status : Exit_Status := Success;
1781
1782    package Buffer is new Table.Table
1783      (Table_Component_Type => Character,
1784       Table_Index_Type     => Integer,
1785       Table_Low_Bound      => 1,
1786       Table_Initial        => 4096,
1787       Table_Increment      => 2,
1788       Table_Name           => "Buffer");
1789
1790    Param_Count : Natural := 0;
1791    --  Number of parameter arguments so far
1792
1793    Arg_Num : Natural;
1794    --  Argument number
1795
1796    Display_Command : Boolean := False;
1797    --  Set true if /? switch causes display of generated command (on VMS)
1798
1799    The_Command : Command_Type;
1800    --  The command used
1801
1802    -----------------------
1803    -- Local Subprograms --
1804    -----------------------
1805
1806    function Index (Char : Character; Str : String) return Natural;
1807    --  Returns the first occurrence of Char in Str.
1808    --  Returns 0 if Char is not in Str.
1809
1810    function Init_Object_Dirs return Argument_List;
1811
1812    function Invert_Sense (S : String) return String_Ptr;
1813    --  Given a unix switch string S, computes the inverse (adding or
1814    --  removing ! characters as required), and returns a pointer to
1815    --  the allocated result on the heap.
1816
1817    function Is_Extensionless (F : String) return Boolean;
1818    --  Returns true if the filename has no extension.
1819
1820    function Match (S1, S2 : String) return Boolean;
1821    --  Determines whether S1 and S2 match. This is a case insensitive match.
1822
1823    function Match_Prefix (S1, S2 : String) return Boolean;
1824    --  Determines whether S1 matches a prefix of S2. This is also a case
1825    --  insensitive match (for example Match ("AB","abc") is True).
1826
1827    function Matching_Name
1828      (S     : String;
1829       Itm   : Item_Ptr;
1830       Quiet : Boolean := False)
1831       return  Item_Ptr;
1832    --  Determines if the item list headed by Itm and threaded through the
1833    --  Next fields (with null marking the end of the list), contains an
1834    --  entry that uniquely matches the given string. The match is case
1835    --  insensitive and permits unique abbreviation. If the match succeeds,
1836    --  then a pointer to the matching item is returned. Otherwise, an
1837    --  appropriate error message is written. Note that the discriminant
1838    --  of Itm is used to determine the appropriate form of this message.
1839    --  Quiet is normally False as shown, if it is set to True, then no
1840    --  error message is generated in a not found situation (null is still
1841    --  returned to indicate the not-found situation).
1842
1843    procedure Non_VMS_Usage;
1844    --  Display usage for platforms other than VMS
1845
1846    function OK_Alphanumerplus (S : String) return Boolean;
1847    --  Checks that S is a string of alphanumeric characters,
1848    --  returning True if all alphanumeric characters,
1849    --  False if empty or a non-alphanumeric character is present.
1850
1851    function OK_Integer (S : String) return Boolean;
1852    --  Checks that S is a string of digits, returning True if all digits,
1853    --  False if empty or a non-digit is present.
1854
1855    procedure Output_Version;
1856    --  Output the version of this program
1857
1858    procedure Place (C : Character);
1859    --  Place a single character in the buffer, updating Ptr
1860
1861    procedure Place (S : String);
1862    --  Place a string character in the buffer, updating Ptr
1863
1864    procedure Place_Lower (S : String);
1865    --  Place string in buffer, forcing letters to lower case, updating Ptr
1866
1867    procedure Place_Unix_Switches (S : String_Ptr);
1868    --  Given a unix switch string, place corresponding switches in Buffer,
1869    --  updating Ptr appropriatelly. Note that in the case of use of ! the
1870    --  result may be to remove a previously placed switch.
1871
1872    procedure Set_Library_For
1873      (Project             : Project_Id;
1874       There_Are_Libraries : in out Boolean);
1875    --  If Project is a library project, add the correct
1876    --  -L and -l switches to the linker invocation.
1877
1878    procedure Set_Libraries is
1879       new For_Every_Project_Imported (Boolean, Set_Library_For);
1880    --  Add the -L and -l switches to the linker for all
1881    --  of the library projects.
1882
1883    procedure Validate_Command_Or_Option (N : String_Ptr);
1884    --  Check that N is a valid command or option name, i.e. that it is of the
1885    --  form of an Ada identifier with upper case letters and underscores.
1886
1887    procedure Validate_Unix_Switch (S : String_Ptr);
1888    --  Check that S is a valid switch string as described in the syntax for
1889    --  the switch table item UNIX_SWITCH or else begins with a backquote.
1890
1891    procedure VMS_Conversion (The_Command : out Command_Type);
1892    --  Converts VMS command line to equivalent Unix command line
1893
1894    -----------
1895    -- Index --
1896    -----------
1897
1898    function Index (Char : Character; Str : String) return Natural is
1899    begin
1900       for Index in Str'Range loop
1901          if Str (Index) = Char then
1902             return Index;
1903          end if;
1904       end loop;
1905
1906       return 0;
1907    end Index;
1908
1909    ----------------------
1910    -- Init_Object_Dirs --
1911    ----------------------
1912
1913    function Init_Object_Dirs return Argument_List is
1914       Object_Dirs     : Integer;
1915       Object_Dir      : Argument_List (1 .. 256);
1916       Object_Dir_Name : String_Access;
1917
1918    begin
1919       Object_Dirs := 0;
1920       Object_Dir_Name := String_Access (Object_Dir_Default_Name);
1921       Get_Next_Dir_In_Path_Init (Object_Dir_Name);
1922
1923       loop
1924          declare
1925             Dir : String_Access := String_Access
1926               (Get_Next_Dir_In_Path (Object_Dir_Name));
1927          begin
1928             exit when Dir = null;
1929             Object_Dirs := Object_Dirs + 1;
1930             Object_Dir (Object_Dirs) :=
1931               new String'("-L" &
1932                           To_Canonical_Dir_Spec
1933                           (To_Host_Dir_Spec
1934                            (Normalize_Directory_Name (Dir.all).all,
1935                             True).all, True).all);
1936          end;
1937       end loop;
1938
1939       Object_Dirs := Object_Dirs + 1;
1940       Object_Dir (Object_Dirs) := new String'("-lgnat");
1941
1942       if Hostparm.OpenVMS then
1943          Object_Dirs := Object_Dirs + 1;
1944          Object_Dir (Object_Dirs) := new String'("-ldecgnat");
1945       end if;
1946
1947       return Object_Dir (1 .. Object_Dirs);
1948    end Init_Object_Dirs;
1949
1950    ------------------
1951    -- Invert_Sense --
1952    ------------------
1953
1954    function Invert_Sense (S : String) return String_Ptr is
1955       Sinv : String (1 .. S'Length * 2);
1956       --  Result (for sure long enough)
1957
1958       Sinvp : Natural := 0;
1959       --  Pointer to output string
1960
1961    begin
1962       for Sp in S'Range loop
1963          if Sp = S'First or else S (Sp - 1) = ',' then
1964             if S (Sp) = '!' then
1965                null;
1966             else
1967                Sinv (Sinvp + 1) := '!';
1968                Sinv (Sinvp + 2) := S (Sp);
1969                Sinvp := Sinvp + 2;
1970             end if;
1971
1972          else
1973             Sinv (Sinvp + 1) := S (Sp);
1974             Sinvp := Sinvp + 1;
1975          end if;
1976       end loop;
1977
1978       return new String'(Sinv (1 .. Sinvp));
1979    end Invert_Sense;
1980
1981    ----------------------
1982    -- Is_Extensionless --
1983    ----------------------
1984
1985    function Is_Extensionless (F : String) return Boolean is
1986    begin
1987       for J in reverse F'Range loop
1988          if F (J) = '.' then
1989             return False;
1990          elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
1991             return True;
1992          end if;
1993       end loop;
1994
1995       return True;
1996    end Is_Extensionless;
1997
1998    -----------
1999    -- Match --
2000    -----------
2001
2002    function Match (S1, S2 : String) return Boolean is
2003       Dif : constant Integer := S2'First - S1'First;
2004
2005    begin
2006
2007       if S1'Length /= S2'Length then
2008          return False;
2009
2010       else
2011          for J in S1'Range loop
2012             if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
2013                return False;
2014             end if;
2015          end loop;
2016
2017          return True;
2018       end if;
2019    end Match;
2020
2021    ------------------
2022    -- Match_Prefix --
2023    ------------------
2024
2025    function Match_Prefix (S1, S2 : String) return Boolean is
2026    begin
2027       if S1'Length > S2'Length then
2028          return False;
2029       else
2030          return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
2031       end if;
2032    end Match_Prefix;
2033
2034    -------------------
2035    -- Matching_Name --
2036    -------------------
2037
2038    function Matching_Name
2039      (S     : String;
2040       Itm   : Item_Ptr;
2041       Quiet : Boolean := False)
2042      return  Item_Ptr
2043    is
2044       P1, P2 : Item_Ptr;
2045
2046       procedure Err;
2047       --  Little procedure to output command/qualifier/option as appropriate
2048       --  and bump error count.
2049
2050       ---------
2051       -- Err --
2052       ---------
2053
2054       procedure Err is
2055       begin
2056          if Quiet then
2057             return;
2058          end if;
2059
2060          Errors := Errors + 1;
2061
2062          if Itm /= null then
2063             case Itm.Id is
2064                when Id_Command =>
2065                   Put (Standard_Error, "command");
2066
2067                when Id_Switch =>
2068                   if OpenVMS then
2069                      Put (Standard_Error, "qualifier");
2070                   else
2071                      Put (Standard_Error, "switch");
2072                   end if;
2073
2074                when Id_Option =>
2075                   Put (Standard_Error, "option");
2076
2077             end case;
2078          else
2079             Put (Standard_Error, "input");
2080
2081          end if;
2082
2083          Put (Standard_Error, ": ");
2084          Put (Standard_Error, S);
2085       end Err;
2086
2087    --  Start of processing for Matching_Name
2088
2089    begin
2090       --  If exact match, that's the one we want
2091
2092       P1 := Itm;
2093       while P1 /= null loop
2094          if Match (S, P1.Name.all) then
2095             return P1;
2096          else
2097             P1 := P1.Next;
2098          end if;
2099       end loop;
2100
2101       --  Now check for prefix matches
2102
2103       P1 := Itm;
2104       while P1 /= null loop
2105          if P1.Name.all = "/<other>" then
2106             return P1;
2107
2108          elsif not Match_Prefix (S, P1.Name.all) then
2109             P1 := P1.Next;
2110
2111          else
2112             --  Here we have found one matching prefix, so see if there is
2113             --  another one (which is an ambiguity)
2114
2115             P2 := P1.Next;
2116             while P2 /= null loop
2117                if Match_Prefix (S, P2.Name.all) then
2118                   if not Quiet then
2119                      Put (Standard_Error, "ambiguous ");
2120                      Err;
2121                      Put (Standard_Error, " (matches ");
2122                      Put (Standard_Error, P1.Name.all);
2123
2124                      while P2 /= null loop
2125                         if Match_Prefix (S, P2.Name.all) then
2126                            Put (Standard_Error, ',');
2127                            Put (Standard_Error, P2.Name.all);
2128                         end if;
2129
2130                         P2 := P2.Next;
2131                      end loop;
2132
2133                      Put_Line (Standard_Error, ")");
2134                   end if;
2135
2136                   return null;
2137                end if;
2138
2139                P2 := P2.Next;
2140             end loop;
2141
2142             --  If we fall through that loop, then there was only one match
2143
2144             return P1;
2145          end if;
2146       end loop;
2147
2148       --  If we fall through outer loop, there was no match
2149
2150       if not Quiet then
2151          Put (Standard_Error, "unrecognized ");
2152          Err;
2153          New_Line (Standard_Error);
2154       end if;
2155
2156       return null;
2157    end Matching_Name;
2158
2159    -----------------------
2160    -- OK_Alphanumerplus --
2161    -----------------------
2162
2163    function OK_Alphanumerplus (S : String) return Boolean is
2164    begin
2165       if S'Length = 0 then
2166          return False;
2167
2168       else
2169          for J in S'Range loop
2170             if not (Is_Alphanumeric (S (J)) or else
2171                     S (J) = '_' or else S (J) = '$')
2172             then
2173                return False;
2174             end if;
2175          end loop;
2176
2177          return True;
2178       end if;
2179    end OK_Alphanumerplus;
2180
2181    ----------------
2182    -- OK_Integer --
2183    ----------------
2184
2185    function OK_Integer (S : String) return Boolean is
2186    begin
2187       if S'Length = 0 then
2188          return False;
2189
2190       else
2191          for J in S'Range loop
2192             if not Is_Digit (S (J)) then
2193                return False;
2194             end if;
2195          end loop;
2196
2197          return True;
2198       end if;
2199    end OK_Integer;
2200
2201    --------------------
2202    -- Output_Version --
2203    --------------------
2204
2205    procedure Output_Version is
2206    begin
2207       Put ("GNAT ");
2208       Put (Gnatvsn.Gnat_Version_String);
2209       Put_Line (" Copyright 1996-2002 Free Software Foundation, Inc.");
2210    end Output_Version;
2211
2212    -----------
2213    -- Place --
2214    -----------
2215
2216    procedure Place (C : Character) is
2217    begin
2218       Buffer.Increment_Last;
2219       Buffer.Table (Buffer.Last) := C;
2220
2221       --  Do not put a space as the first character in the buffer
2222       if C = ' ' and then Buffer.Last = 1 then
2223          Buffer.Decrement_Last;
2224       end if;
2225    end Place;
2226
2227    procedure Place (S : String) is
2228    begin
2229       for J in S'Range loop
2230          Place (S (J));
2231       end loop;
2232    end Place;
2233
2234    -----------------
2235    -- Place_Lower --
2236    -----------------
2237
2238    procedure Place_Lower (S : String) is
2239    begin
2240       for J in S'Range loop
2241          Place (To_Lower (S (J)));
2242       end loop;
2243    end Place_Lower;
2244
2245    -------------------------
2246    -- Place_Unix_Switches --
2247    -------------------------
2248
2249    procedure Place_Unix_Switches (S : String_Ptr) is
2250       P1, P2, P3 : Natural;
2251       Remove     : Boolean;
2252       Slen       : Natural;
2253
2254    begin
2255       P1 := S'First;
2256       while P1 <= S'Last loop
2257          if S (P1) = '!' then
2258             P1 := P1 + 1;
2259             Remove := True;
2260          else
2261             Remove := False;
2262          end if;
2263
2264          P2 := P1;
2265          pragma Assert (S (P1) = '-' or else S (P1) = '`');
2266
2267          while P2 < S'Last and then S (P2 + 1) /= ',' loop
2268             P2 := P2 + 1;
2269          end loop;
2270
2271          --  Switch is now in S (P1 .. P2)
2272
2273          Slen := P2 - P1 + 1;
2274
2275          if Remove then
2276             P3 := 2;
2277             while P3 <= Buffer.Last - Slen loop
2278                if Buffer.Table (P3) = ' '
2279                  and then String (Buffer.Table (P3 + 1 .. P3 + Slen)) =
2280                                                              S (P1 .. P2)
2281                  and then (P3 + Slen = Buffer.Last
2282                              or else
2283                            Buffer.Table (P3 + Slen + 1) = ' ')
2284                then
2285                   Buffer.Table (P3 .. Buffer.Last - Slen - 1) :=
2286                     Buffer.Table (P3 + Slen + 1 .. Buffer.Last);
2287                   Buffer.Set_Last (Buffer.Last - Slen - 1);
2288
2289                else
2290                   P3 := P3 + 1;
2291                end if;
2292             end loop;
2293
2294          else
2295             Place (' ');
2296
2297             if S (P1) = '`' then
2298                P1 := P1 + 1;
2299             end if;
2300
2301             Place (S (P1 .. P2));
2302          end if;
2303
2304          P1 := P2 + 2;
2305       end loop;
2306    end Place_Unix_Switches;
2307
2308    ---------------------
2309    -- Set_Library_For --
2310    ---------------------
2311
2312    procedure Set_Library_For
2313      (Project             : Project_Id;
2314       There_Are_Libraries : in out Boolean)
2315    is
2316    begin
2317       --  Case of library project
2318
2319       if Projects.Table (Project).Library then
2320          There_Are_Libraries := True;
2321
2322          --  Add the -L switch
2323
2324          Last_Switches.Increment_Last;
2325          Last_Switches.Table (Last_Switches.Last) :=
2326            new String'("-L" &
2327                        Get_Name_String
2328                        (Projects.Table (Project).Library_Dir));
2329
2330          --  Add the -l switch
2331
2332          Last_Switches.Increment_Last;
2333          Last_Switches.Table (Last_Switches.Last) :=
2334            new String'("-l" &
2335                        Get_Name_String
2336                        (Projects.Table (Project).Library_Name));
2337
2338          --  Add the Wl,-rpath switch if library non static
2339
2340          if Projects.Table (Project).Library_Kind /= Static then
2341             declare
2342                Option : constant String_Access :=
2343                           MLib.Tgt.Linker_Library_Path_Option
2344                             (Get_Name_String
2345                               (Projects.Table (Project).Library_Dir));
2346
2347             begin
2348                if Option /= null then
2349                   Last_Switches.Increment_Last;
2350                   Last_Switches.Table (Last_Switches.Last) :=
2351                     Option;
2352                end if;
2353
2354             end;
2355
2356          end if;
2357
2358       end if;
2359    end Set_Library_For;
2360
2361    --------------------------------
2362    -- Validate_Command_Or_Option --
2363    --------------------------------
2364
2365    procedure Validate_Command_Or_Option (N : String_Ptr) is
2366    begin
2367       pragma Assert (N'Length > 0);
2368
2369       for J in N'Range loop
2370          if N (J) = '_' then
2371             pragma Assert (N (J - 1) /= '_');
2372             null;
2373          else
2374             pragma Assert (Is_Upper (N (J)) or else Is_Digit (N (J)));
2375             null;
2376          end if;
2377       end loop;
2378    end Validate_Command_Or_Option;
2379
2380    --------------------------
2381    -- Validate_Unix_Switch --
2382    --------------------------
2383
2384    procedure Validate_Unix_Switch (S : String_Ptr) is
2385    begin
2386       if S (S'First) = '`' then
2387          return;
2388       end if;
2389
2390       pragma Assert (S (S'First) = '-' or else S (S'First) = '!');
2391
2392       for J in S'First + 1 .. S'Last loop
2393          pragma Assert (S (J) /= ' ');
2394
2395          if S (J) = '!' then
2396             pragma Assert (S (J - 1) = ',' and then S (J + 1) = '-');
2397             null;
2398          end if;
2399       end loop;
2400    end Validate_Unix_Switch;
2401
2402    ----------------------
2403    -- List of Commands --
2404    ----------------------
2405
2406    --  Note that we put this after all the local bodies (except Non_VMS_Usage
2407    --  and VMS_Conversion that use Command_List) to avoid some access before
2408    --  elaboration problems.
2409
2410    Command_List : constant array (Real_Command_Type) of Command_Entry :=
2411      (Bind =>
2412        (Cname    => new S'("BIND"),
2413         Usage    => new S'("GNAT BIND file[.ali] /qualifiers"),
2414         VMS_Only => False,
2415         Unixcmd  => new S'("gnatbind"),
2416         Unixsws  => null,
2417         Switches => Bind_Switches'Access,
2418         Params   => new Parameter_Array'(1 => File),
2419         Defext   => "ali"),
2420
2421       Chop =>
2422         (Cname    => new S'("CHOP"),
2423          Usage    => new S'("GNAT CHOP file [directory] /qualifiers"),
2424          VMS_Only => False,
2425          Unixcmd  => new S'("gnatchop"),
2426          Unixsws  => null,
2427          Switches => Chop_Switches'Access,
2428          Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
2429          Defext   => "   "),
2430
2431       Compile =>
2432         (Cname    => new S'("COMPILE"),
2433          Usage    => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
2434          VMS_Only => False,
2435          Unixcmd  => new S'("gnatmake"),
2436          Unixsws  => new Argument_List' (1 => new String'("-f"),
2437                                          2 => new String'("-u"),
2438                                          3 => new String'("-c")),
2439          Switches => GCC_Switches'Access,
2440          Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
2441          Defext   => "   "),
2442
2443       Elim =>
2444         (Cname    => new S'("ELIM"),
2445          Usage    => new S'("GNAT ELIM name /qualifiers"),
2446          VMS_Only => False,
2447          Unixcmd  => new S'("gnatelim"),
2448          Unixsws  => null,
2449          Switches => Elim_Switches'Access,
2450          Params   => new Parameter_Array'(1 => Other_As_Is),
2451          Defext   => "ali"),
2452
2453       Find =>
2454         (Cname    => new S'("FIND"),
2455          Usage    => new S'("GNAT FIND pattern[:sourcefile[:line"
2456                             & "[:column]]] filespec[,...] /qualifiers"),
2457          VMS_Only => False,
2458          Unixcmd  => new S'("gnatfind"),
2459          Unixsws  => null,
2460          Switches => Find_Switches'Access,
2461          Params   => new Parameter_Array'(1 => Other_As_Is,
2462                                           2 => Files_Or_Wildcard),
2463          Defext   => "ali"),
2464
2465       Krunch =>
2466         (Cname    => new S'("KRUNCH"),
2467          Usage    => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
2468          VMS_Only => False,
2469          Unixcmd  => new S'("gnatkr"),
2470          Unixsws  => null,
2471          Switches => Krunch_Switches'Access,
2472          Params   => new Parameter_Array'(1 => File),
2473          Defext   => "   "),
2474
2475       Library =>
2476         (Cname    => new S'("LIBRARY"),
2477          Usage    => new S'("GNAT LIBRARY /[CREATE | SET | DELETE]"
2478                             & "=directory [/CONFIG=file]"),
2479          VMS_Only => True,
2480          Unixcmd  => new S'("gnatlbr"),
2481          Unixsws  => null,
2482          Switches => Lbr_Switches'Access,
2483          Params   => new Parameter_Array'(1 .. 0 => File),
2484          Defext   => "   "),
2485
2486       Link =>
2487         (Cname    => new S'("LINK"),
2488          Usage    => new S'("GNAT LINK file[.ali]"
2489                             & " [extra obj_&_lib_&_exe_&_opt files]"
2490                             & " /qualifiers"),
2491          VMS_Only => False,
2492          Unixcmd  => new S'("gnatlink"),
2493          Unixsws  => null,
2494          Switches => Link_Switches'Access,
2495          Params   => new Parameter_Array'(1 => Unlimited_Files),
2496          Defext   => "ali"),
2497
2498       List =>
2499         (Cname    => new S'("LIST"),
2500          Usage    => new S'("GNAT LIST /qualifiers object_or_ali_file"),
2501          VMS_Only => False,
2502          Unixcmd  => new S'("gnatls"),
2503          Unixsws  => null,
2504          Switches => List_Switches'Access,
2505          Params   => new Parameter_Array'(1 => File),
2506          Defext   => "ali"),
2507
2508       Make =>
2509         (Cname    => new S'("MAKE"),
2510          Usage    => new S'("GNAT MAKE file /qualifiers (includes "
2511                             & "COMPILE /qualifiers)"),
2512          VMS_Only => False,
2513          Unixcmd  => new S'("gnatmake"),
2514          Unixsws  => null,
2515          Switches => Make_Switches'Access,
2516          Params   => new Parameter_Array'(1 => File),
2517          Defext   => "   "),
2518
2519       Name =>
2520         (Cname    => new S'("NAME"),
2521          Usage    => new S'("GNAT NAME /qualifiers naming-pattern "
2522                             & "[naming-patterns]"),
2523          VMS_Only => False,
2524          Unixcmd  => new S'("gnatname"),
2525          Unixsws  => null,
2526          Switches => Name_Switches'Access,
2527          Params   => new Parameter_Array'(1 => Unlimited_As_Is),
2528          Defext   => "   "),
2529
2530       Preprocess =>
2531         (Cname    => new S'("PREPROCESS"),
2532          Usage    => new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
2533          VMS_Only => False,
2534          Unixcmd  => new S'("gnatprep"),
2535          Unixsws  => null,
2536          Switches => Prep_Switches'Access,
2537          Params   => new Parameter_Array'(1 .. 3 => File),
2538          Defext   => "   "),
2539
2540       Shared =>
2541         (Cname    => new S'("SHARED"),
2542          Usage    => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt"
2543                             & "files] /qualifiers"),
2544          VMS_Only => True,
2545          Unixcmd  => new S'("gcc"),
2546          Unixsws  => new Argument_List'(new String'("-shared")
2547                                         & Init_Object_Dirs),
2548          Switches => Shared_Switches'Access,
2549          Params   => new Parameter_Array'(1 => Unlimited_Files),
2550          Defext   => "   "),
2551
2552       Standard =>
2553         (Cname    => new S'("STANDARD"),
2554          Usage    => new S'("GNAT STANDARD"),
2555          VMS_Only => False,
2556          Unixcmd  => new S'("gnatpsta"),
2557          Unixsws  => null,
2558          Switches => Standard_Switches'Access,
2559          Params   => new Parameter_Array'(1 .. 0 => File),
2560          Defext   => "   "),
2561
2562       Stub =>
2563         (Cname    => new S'("STUB"),
2564          Usage    => new S'("GNAT STUB file [directory]/qualifiers"),
2565          VMS_Only => False,
2566          Unixcmd  => new S'("gnatstub"),
2567          Unixsws  => null,
2568          Switches => Stub_Switches'Access,
2569          Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
2570          Defext   => "   "),
2571
2572       Xref =>
2573         (Cname    => new S'("XREF"),
2574          Usage    => new S'("GNAT XREF filespec[,...] /qualifiers"),
2575          VMS_Only => False,
2576          Unixcmd  => new S'("gnatxref"),
2577          Unixsws  => null,
2578          Switches => Xref_Switches'Access,
2579          Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
2580          Defext   => "ali")
2581       );
2582
2583    -------------------
2584    -- Non_VMS_Usage --
2585    -------------------
2586
2587    procedure Non_VMS_Usage is
2588    begin
2589       Output_Version;
2590       New_Line;
2591       Put_Line ("List of available commands");
2592       New_Line;
2593
2594       for C in Command_List'Range loop
2595          if not Command_List (C).VMS_Only then
2596             Put ("GNAT " & Command_List (C).Cname.all);
2597             Set_Col (25);
2598             Put (Command_List (C).Unixcmd.all);
2599
2600             declare
2601                Sws : Argument_List_Access renames Command_List (C).Unixsws;
2602             begin
2603                if Sws /= null then
2604                   for J in Sws'Range loop
2605                      Put (' ');
2606                      Put (Sws (J).all);
2607                   end loop;
2608                end if;
2609             end;
2610
2611             New_Line;
2612          end if;
2613       end loop;
2614
2615       New_Line;
2616       Put_Line ("Commands FIND, LIST and XREF accept project file " &
2617                 "switches -vPx, -Pprj and -Xnam=val");
2618       New_Line;
2619    end Non_VMS_Usage;
2620
2621    --------------------
2622    -- VMS_Conversion --
2623    --------------------
2624
2625    procedure VMS_Conversion (The_Command : out Command_Type) is
2626    begin
2627       Buffer.Init;
2628
2629       --  First we must preprocess the string form of the command and options
2630       --  list into the internal form that we use.
2631
2632       for C in Real_Command_Type loop
2633
2634          declare
2635             Command : Item_Ptr := new Command_Item;
2636
2637             Last_Switch : Item_Ptr;
2638             --  Last switch in list
2639
2640          begin
2641             --  Link new command item into list of commands
2642
2643             if Last_Command = null then
2644                Commands := Command;
2645             else
2646                Last_Command.Next := Command;
2647             end if;
2648
2649             Last_Command := Command;
2650
2651             --  Fill in fields of new command item
2652
2653             Command.Name    := Command_List (C).Cname;
2654             Command.Usage   := Command_List (C).Usage;
2655             Command.Command := C;
2656
2657             if Command_List (C).Unixsws = null then
2658                Command.Unix_String := Command_List (C).Unixcmd;
2659             else
2660                declare
2661                   Cmd  : String (1 .. 5_000);
2662                   Last : Natural := 0;
2663                   Sws  : Argument_List_Access := Command_List (C).Unixsws;
2664
2665                begin
2666                   Cmd (1 .. Command_List (C).Unixcmd'Length) :=
2667                     Command_List (C).Unixcmd.all;
2668                   Last := Command_List (C).Unixcmd'Length;
2669
2670                   for J in Sws'Range loop
2671                      Last := Last + 1;
2672                      Cmd (Last) := ' ';
2673                      Cmd (Last + 1 .. Last + Sws (J)'Length) :=
2674                        Sws (J).all;
2675                      Last := Last + Sws (J)'Length;
2676                   end loop;
2677
2678                   Command.Unix_String := new String'(Cmd (1 .. Last));
2679                end;
2680             end if;
2681
2682             Command.Params := Command_List (C).Params;
2683             Command.Defext := Command_List (C).Defext;
2684
2685             Validate_Command_Or_Option (Command.Name);
2686
2687             --  Process the switch list
2688
2689             for S in Command_List (C).Switches'Range loop
2690                declare
2691                   SS : constant String_Ptr := Command_List (C).Switches (S);
2692
2693                   P  : Natural := SS'First;
2694                   Sw : Item_Ptr := new Switch_Item;
2695
2696                   Last_Opt : Item_Ptr;
2697                   --  Pointer to last option
2698
2699                begin
2700                   --  Link new switch item into list of switches
2701
2702                   if Last_Switch = null then
2703                      Command.Switches := Sw;
2704                   else
2705                      Last_Switch.Next := Sw;
2706                   end if;
2707
2708                   Last_Switch := Sw;
2709
2710                   --  Process switch string, first get name
2711
2712                   while SS (P) /= ' ' and SS (P) /= '=' loop
2713                      P := P + 1;
2714                   end loop;
2715
2716                   Sw.Name := new String'(SS (SS'First .. P - 1));
2717
2718                   --  Direct translation case
2719
2720                   if SS (P) = ' ' then
2721                      Sw.Translation := T_Direct;
2722                      Sw.Unix_String := new String'(SS (P + 1 .. SS'Last));
2723                      Validate_Unix_Switch (Sw.Unix_String);
2724
2725                      if SS (P - 1) = '>' then
2726                         Sw.Translation := T_Other;
2727
2728                      elsif SS (P + 1) = '`' then
2729                         null;
2730
2731                         --  Create the inverted case (/NO ..)
2732
2733                      elsif SS (SS'First + 1 .. SS'First + 2) /= "NO" then
2734                         Sw := new Switch_Item;
2735                         Last_Switch.Next := Sw;
2736                         Last_Switch := Sw;
2737
2738                         Sw.Name :=
2739                           new String'("/NO" & SS (SS'First + 1 .. P - 1));
2740                         Sw.Translation := T_Direct;
2741                         Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
2742                         Validate_Unix_Switch (Sw.Unix_String);
2743                      end if;
2744
2745                      --  Directories translation case
2746
2747                   elsif SS (P + 1) = '*' then
2748                      pragma Assert (SS (SS'Last) = '*');
2749                      Sw.Translation := T_Directories;
2750                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2751                      Validate_Unix_Switch (Sw.Unix_String);
2752
2753                      --  Directory translation case
2754
2755                   elsif SS (P + 1) = '%' then
2756                      pragma Assert (SS (SS'Last) = '%');
2757                      Sw.Translation := T_Directory;
2758                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2759                      Validate_Unix_Switch (Sw.Unix_String);
2760
2761                      --  File translation case
2762
2763                   elsif SS (P + 1) = '@' then
2764                      pragma Assert (SS (SS'Last) = '@');
2765                      Sw.Translation := T_File;
2766                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2767                      Validate_Unix_Switch (Sw.Unix_String);
2768
2769                      --  No space file translation case
2770
2771                   elsif SS (P + 1) = '<' then
2772                      pragma Assert (SS (SS'Last) = '>');
2773                      Sw.Translation := T_No_Space_File;
2774                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2775                      Validate_Unix_Switch (Sw.Unix_String);
2776
2777                      --  Numeric translation case
2778
2779                   elsif SS (P + 1) = '#' then
2780                      pragma Assert (SS (SS'Last) = '#');
2781                      Sw.Translation := T_Numeric;
2782                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2783                      Validate_Unix_Switch (Sw.Unix_String);
2784
2785                      --  Alphanumerplus translation case
2786
2787                   elsif SS (P + 1) = '|' then
2788                      pragma Assert (SS (SS'Last) = '|');
2789                      Sw.Translation := T_Alphanumplus;
2790                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2791                      Validate_Unix_Switch (Sw.Unix_String);
2792
2793                      --  String translation case
2794
2795                   elsif SS (P + 1) = '"' then
2796                      pragma Assert (SS (SS'Last) = '"');
2797                      Sw.Translation := T_String;
2798                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2799                      Validate_Unix_Switch (Sw.Unix_String);
2800
2801                      --  Commands translation case
2802
2803                   elsif SS (P + 1) = '?' then
2804                      Sw.Translation := T_Commands;
2805                      Sw.Unix_String := new String'(SS (P + 2 .. SS'Last));
2806
2807                      --  Options translation case
2808
2809                   else
2810                      Sw.Translation := T_Options;
2811                      Sw.Unix_String := new String'("");
2812
2813                      P := P + 1; -- bump past =
2814                      while P <= SS'Last loop
2815                         declare
2816                            Opt : Item_Ptr := new Option_Item;
2817                            Q   : Natural;
2818
2819                         begin
2820                            --  Link new option item into options list
2821
2822                            if Last_Opt = null then
2823                               Sw.Options := Opt;
2824                            else
2825                               Last_Opt.Next := Opt;
2826                            end if;
2827
2828                            Last_Opt := Opt;
2829
2830                            --  Fill in fields of new option item
2831
2832                            Q := P;
2833                            while SS (Q) /= ' ' loop
2834                               Q := Q + 1;
2835                            end loop;
2836
2837                            Opt.Name := new String'(SS (P .. Q - 1));
2838                            Validate_Command_Or_Option (Opt.Name);
2839
2840                            P := Q + 1;
2841                            Q := P;
2842
2843                            while Q <= SS'Last and then SS (Q) /= ' ' loop
2844                               Q := Q + 1;
2845                            end loop;
2846
2847                            Opt.Unix_String := new String'(SS (P .. Q - 1));
2848                            Validate_Unix_Switch (Opt.Unix_String);
2849                            P := Q + 1;
2850                         end;
2851                      end loop;
2852                   end if;
2853                end;
2854             end loop;
2855          end;
2856       end loop;
2857
2858       --  If no parameters, give complete list of commands
2859
2860       if Argument_Count = 0 then
2861          Output_Version;
2862          New_Line;
2863          Put_Line ("List of available commands");
2864          New_Line;
2865
2866          while Commands /= null loop
2867             Put (Commands.Usage.all);
2868             Set_Col (53);
2869             Put_Line (Commands.Unix_String.all);
2870             Commands := Commands.Next;
2871          end loop;
2872
2873          raise Normal_Exit;
2874       end if;
2875
2876       Arg_Num := 1;
2877
2878       --  Loop through arguments
2879
2880       while Arg_Num <= Argument_Count loop
2881
2882          Process_Argument : declare
2883             Argv    : String_Access;
2884             Arg_Idx : Integer;
2885
2886             function Get_Arg_End
2887               (Argv    : String;
2888                Arg_Idx : Integer)
2889                return    Integer;
2890             --  Begins looking at Arg_Idx + 1 and returns the index of the
2891             --  last character before a slash or else the index of the last
2892             --  character in the string Argv.
2893
2894             -----------------
2895             -- Get_Arg_End --
2896             -----------------
2897
2898             function Get_Arg_End
2899               (Argv    : String;
2900                Arg_Idx : Integer)
2901               return    Integer
2902             is
2903             begin
2904                for J in Arg_Idx + 1 .. Argv'Last loop
2905                   if Argv (J) = '/' then
2906                      return J - 1;
2907                   end if;
2908                end loop;
2909
2910                return Argv'Last;
2911             end Get_Arg_End;
2912
2913          --  Start of processing for Process_Argument
2914
2915          begin
2916             Argv := new String'(Argument (Arg_Num));
2917             Arg_Idx := Argv'First;
2918
2919             <<Tryagain_After_Coalesce>>
2920                loop
2921                   declare
2922                      Next_Arg_Idx : Integer;
2923                      Arg          : String_Access;
2924
2925                   begin
2926                      Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
2927                      Arg := new String'(Argv (Arg_Idx .. Next_Arg_Idx));
2928
2929                      --  The first one must be a command name
2930
2931                      if Arg_Num = 1 and then Arg_Idx = Argv'First then
2932
2933                         Command := Matching_Name (Arg.all, Commands);
2934
2935                         if Command = null then
2936                            raise Error_Exit;
2937                         end if;
2938
2939                         The_Command := Command.Command;
2940
2941                         --  Give usage information if only command given
2942
2943                         if Argument_Count = 1 and then Next_Arg_Idx = Argv'Last
2944                           and then Command.Command /= Standard
2945                         then
2946                            Output_Version;
2947                            New_Line;
2948                            Put_Line
2949                              ("List of available qualifiers and options");
2950                            New_Line;
2951
2952                            Put (Command.Usage.all);
2953                            Set_Col (53);
2954                            Put_Line (Command.Unix_String.all);
2955
2956                            declare
2957                               Sw : Item_Ptr := Command.Switches;
2958
2959                            begin
2960                               while Sw /= null loop
2961                                  Put ("   ");
2962                                  Put (Sw.Name.all);
2963
2964                                  case Sw.Translation is
2965
2966                                     when T_Other =>
2967                                        Set_Col (53);
2968                                        Put_Line (Sw.Unix_String.all &
2969                                                  "/<other>");
2970
2971                                     when T_Direct =>
2972                                        Set_Col (53);
2973                                        Put_Line (Sw.Unix_String.all);
2974
2975                                     when T_Directories =>
2976                                        Put ("=(direc,direc,..direc)");
2977                                        Set_Col (53);
2978                                        Put (Sw.Unix_String.all);
2979                                        Put (" direc ");
2980                                        Put (Sw.Unix_String.all);
2981                                        Put_Line (" direc ...");
2982
2983                                     when T_Directory =>
2984                                        Put ("=directory");
2985                                        Set_Col (53);
2986                                        Put (Sw.Unix_String.all);
2987
2988                                        if Sw.Unix_String (Sw.Unix_String'Last)
2989                                          /= '='
2990                                        then
2991                                           Put (' ');
2992                                        end if;
2993
2994                                        Put_Line ("directory ");
2995
2996                                     when T_File | T_No_Space_File =>
2997                                        Put ("=file");
2998                                        Set_Col (53);
2999                                        Put (Sw.Unix_String.all);
3000
3001                                        if Sw.Translation = T_File
3002                                          and then Sw.Unix_String
3003                                                    (Sw.Unix_String'Last)
3004                                                      /= '='
3005                                        then
3006                                           Put (' ');
3007                                        end if;
3008
3009                                        Put_Line ("file ");
3010
3011                                     when T_Numeric =>
3012                                        Put ("=nnn");
3013                                        Set_Col (53);
3014
3015                                        if Sw.Unix_String (Sw.Unix_String'First)
3016                                          = '`'
3017                                        then
3018                                           Put (Sw.Unix_String
3019                                                (Sw.Unix_String'First + 1
3020                                                 .. Sw.Unix_String'Last));
3021                                        else
3022                                           Put (Sw.Unix_String.all);
3023                                        end if;
3024
3025                                        Put_Line ("nnn");
3026
3027                                     when T_Alphanumplus =>
3028                                        Put ("=xyz");
3029                                        Set_Col (53);
3030
3031                                        if Sw.Unix_String (Sw.Unix_String'First)
3032                                          = '`'
3033                                        then
3034                                           Put (Sw.Unix_String
3035                                                (Sw.Unix_String'First + 1
3036                                                 .. Sw.Unix_String'Last));
3037                                        else
3038                                           Put (Sw.Unix_String.all);
3039                                        end if;
3040
3041                                        Put_Line ("xyz");
3042
3043                                     when T_String =>
3044                                        Put ("=");
3045                                        Put ('"');
3046                                        Put ("<string>");
3047                                        Put ('"');
3048                                        Set_Col (53);
3049
3050                                        Put (Sw.Unix_String.all);
3051
3052                                        if Sw.Unix_String (Sw.Unix_String'Last)
3053                                          /= '='
3054                                        then
3055                                           Put (' ');
3056                                        end if;
3057
3058                                        Put ("<string>");
3059                                        New_Line;
3060
3061                                     when T_Commands =>
3062                                        Put (" (switches for ");
3063                                        Put (Sw.Unix_String
3064                                             (Sw.Unix_String'First + 7
3065                                              .. Sw.Unix_String'Last));
3066                                        Put (')');
3067                                        Set_Col (53);
3068                                        Put (Sw.Unix_String
3069                                             (Sw.Unix_String'First
3070                                              .. Sw.Unix_String'First + 5));
3071                                        Put_Line (" switches");
3072
3073                                     when T_Options =>
3074                                        declare
3075                                           Opt : Item_Ptr := Sw.Options;
3076
3077                                        begin
3078                                           Put_Line ("=(option,option..)");
3079
3080                                           while Opt /= null loop
3081                                              Put ("      ");
3082                                              Put (Opt.Name.all);
3083
3084                                              if Opt = Sw.Options then
3085                                                 Put (" (D)");
3086                                              end if;
3087
3088                                              Set_Col (53);
3089                                              Put_Line (Opt.Unix_String.all);
3090                                              Opt := Opt.Next;
3091                                           end loop;
3092                                        end;
3093
3094                                  end case;
3095
3096                                  Sw := Sw.Next;
3097                               end loop;
3098                            end;
3099
3100                            raise Normal_Exit;
3101                         end if;
3102
3103                         --  Place (Command.Unix_String.all);
3104
3105                         --  Special handling for internal debugging switch /?
3106
3107                      elsif Arg.all = "/?" then
3108                         Display_Command := True;
3109
3110                         --  Copy -switch unchanged
3111
3112                      elsif Arg (Arg'First) = '-' then
3113                         Place (' ');
3114                         Place (Arg.all);
3115
3116                         --  Copy quoted switch with quotes stripped
3117
3118                      elsif Arg (Arg'First) = '"' then
3119                         if Arg (Arg'Last) /= '"' then
3120                            Put (Standard_Error, "misquoted argument: ");
3121                            Put_Line (Standard_Error, Arg.all);
3122                            Errors := Errors + 1;
3123
3124                         else
3125                            Place (' ');
3126                            Place (Arg (Arg'First + 1 .. Arg'Last - 1));
3127                         end if;
3128
3129                         --  Parameter Argument
3130
3131                      elsif Arg (Arg'First) /= '/'
3132                        and then Make_Commands_Active = null
3133                      then
3134                         Param_Count := Param_Count + 1;
3135
3136                         if Param_Count <= Command.Params'Length then
3137
3138                            case Command.Params (Param_Count) is
3139
3140                               when File | Optional_File =>
3141                                  declare
3142                                     Normal_File : String_Access
3143                                       := To_Canonical_File_Spec (Arg.all);
3144                                  begin
3145                                     Place (' ');
3146                                     Place_Lower (Normal_File.all);
3147
3148                                     if Is_Extensionless (Normal_File.all)
3149                                       and then Command.Defext /= "   "
3150                                     then
3151                                        Place ('.');
3152                                        Place (Command.Defext);
3153                                     end if;
3154                                  end;
3155
3156                               when Unlimited_Files =>
3157                                  declare
3158                                     Normal_File : String_Access
3159                                       := To_Canonical_File_Spec (Arg.all);
3160
3161                                     File_Is_Wild  : Boolean := False;
3162                                     File_List     : String_Access_List_Access;
3163                                  begin
3164                                     for I in Arg'Range loop
3165                                        if Arg (I) = '*'
3166                                          or else Arg (I) = '%'
3167                                        then
3168                                           File_Is_Wild := True;
3169                                        end if;
3170                                     end loop;
3171
3172                                     if File_Is_Wild then
3173                                        File_List := To_Canonical_File_List
3174                                          (Arg.all, False);
3175
3176                                        for I in File_List.all'Range loop
3177                                           Place (' ');
3178                                           Place_Lower (File_List.all (I).all);
3179                                        end loop;
3180                                     else
3181                                        Place (' ');
3182                                        Place_Lower (Normal_File.all);
3183
3184                                        if Is_Extensionless (Normal_File.all)
3185                                          and then Command.Defext /= "   "
3186                                        then
3187                                           Place ('.');
3188                                           Place (Command.Defext);
3189                                        end if;
3190                                     end if;
3191
3192                                     Param_Count := Param_Count - 1;
3193                                  end;
3194
3195                               when Other_As_Is =>
3196                                  Place (' ');
3197                                  Place (Arg.all);
3198
3199                               when Unlimited_As_Is =>
3200                                  Place (' ');
3201                                  Place (Arg.all);
3202                                  Param_Count := Param_Count - 1;
3203
3204                               when Files_Or_Wildcard =>
3205
3206                                  --  Remove spaces from a comma separated list
3207                                  --  of file names and adjust control variables
3208                                  --  accordingly.
3209
3210                                  while Arg_Num < Argument_Count and then
3211                                    (Argv (Argv'Last) = ',' xor
3212                                     Argument (Arg_Num + 1)
3213                                       (Argument (Arg_Num + 1)'First) = ',')
3214                                  loop
3215                                     Argv := new String'
3216                                            (Argv.all & Argument (Arg_Num + 1));
3217                                     Arg_Num := Arg_Num + 1;
3218                                     Arg_Idx := Argv'First;
3219                                     Next_Arg_Idx :=
3220                                       Get_Arg_End (Argv.all, Arg_Idx);
3221                                     Arg := new String'
3222                                             (Argv (Arg_Idx .. Next_Arg_Idx));
3223                                  end loop;
3224
3225                                  --  Parse the comma separated list of VMS
3226                                  --  filenames and place them on the command
3227                                  --  line as space separated Unix style
3228                                  --  filenames. Lower case and add default
3229                                  --  extension as appropriate.
3230
3231                                  declare
3232                                     Arg1_Idx : Integer := Arg'First;
3233
3234                                     function Get_Arg1_End
3235                                       (Arg : String; Arg_Idx : Integer)
3236                                       return Integer;
3237                                     --  Begins looking at Arg_Idx + 1 and
3238                                     --  returns the index of the last character
3239                                     --  before a comma or else the index of the
3240                                     --  last character in the string Arg.
3241
3242                                     function Get_Arg1_End
3243                                       (Arg : String; Arg_Idx : Integer)
3244                                       return Integer
3245                                     is
3246                                     begin
3247                                        for I in Arg_Idx + 1 .. Arg'Last loop
3248                                           if Arg (I) = ',' then
3249                                              return I - 1;
3250                                           end if;
3251                                        end loop;
3252
3253                                        return Arg'Last;
3254                                     end Get_Arg1_End;
3255
3256                                  begin
3257                                     loop
3258                                        declare
3259                                           Next_Arg1_Idx : Integer :=
3260                                             Get_Arg1_End (Arg.all, Arg1_Idx);
3261
3262                                           Arg1 : String :=
3263                                             Arg (Arg1_Idx .. Next_Arg1_Idx);
3264
3265                                           Normal_File : String_Access :=
3266                                             To_Canonical_File_Spec (Arg1);
3267
3268                                        begin
3269                                           Place (' ');
3270                                           Place_Lower (Normal_File.all);
3271
3272                                           if Is_Extensionless (Normal_File.all)
3273                                             and then Command.Defext /= "   "
3274                                           then
3275                                              Place ('.');
3276                                              Place (Command.Defext);
3277                                           end if;
3278
3279                                           Arg1_Idx := Next_Arg1_Idx + 1;
3280                                        end;
3281
3282                                        exit when Arg1_Idx > Arg'Last;
3283
3284                                        --  Don't allow two or more commas in
3285                                        --  a row
3286
3287                                        if Arg (Arg1_Idx) = ',' then
3288                                           Arg1_Idx := Arg1_Idx + 1;
3289                                           if Arg1_Idx > Arg'Last or else
3290                                             Arg (Arg1_Idx) = ','
3291                                           then
3292                                              Put_Line
3293                                                (Standard_Error,
3294                                                 "Malformed Parameter: " &
3295                                                 Arg.all);
3296                                              Put (Standard_Error, "usage: ");
3297                                              Put_Line (Standard_Error,
3298                                                        Command.Usage.all);
3299                                              raise Error_Exit;
3300                                           end if;
3301                                        end if;
3302
3303                                     end loop;
3304                                  end;
3305                            end case;
3306                         end if;
3307
3308                         --  Qualifier argument
3309
3310                      else
3311                         declare
3312                            Sw   : Item_Ptr;
3313                            SwP  : Natural;
3314                            P2   : Natural;
3315                            Endp : Natural := 0; -- avoid warning!
3316                            Opt  : Item_Ptr;
3317
3318                         begin
3319                            SwP := Arg'First;
3320                            while SwP < Arg'Last
3321                              and then Arg (SwP + 1) /= '='
3322                            loop
3323                               SwP := SwP + 1;
3324                            end loop;
3325
3326                            --  At this point, the switch name is in
3327                            --  Arg (Arg'First..SwP) and if that is not the
3328                            --  whole switch, then there is an equal sign at
3329                            --  Arg (SwP + 1) and the rest of Arg is what comes
3330                            --  after the equal sign.
3331
3332                            --  If make commands are active, see if we have
3333                            --  another COMMANDS_TRANSLATION switch belonging
3334                            --  to gnatmake.
3335
3336                            if Make_Commands_Active /= null then
3337                               Sw :=
3338                                 Matching_Name
3339                                 (Arg (Arg'First .. SwP),
3340                                  Command.Switches,
3341                                  Quiet => True);
3342
3343                               if Sw /= null
3344                                 and then Sw.Translation = T_Commands
3345                               then
3346                                  null;
3347
3348                               else
3349                                  Sw :=
3350                                    Matching_Name
3351                                    (Arg (Arg'First .. SwP),
3352                                     Make_Commands_Active.Switches,
3353                                     Quiet => False);
3354                               end if;
3355
3356                               --  For case of GNAT MAKE or CHOP, if we cannot
3357                               --  find the switch, then see if it is a
3358                               --  recognized compiler switch instead, and if
3359                               --  so process the compiler switch.
3360
3361                            elsif Command.Name.all = "MAKE"
3362                              or else Command.Name.all = "CHOP" then
3363                               Sw :=
3364                                 Matching_Name
3365                                 (Arg (Arg'First .. SwP),
3366                                  Command.Switches,
3367                                  Quiet => True);
3368
3369                               if Sw = null then
3370                                  Sw :=
3371                                    Matching_Name
3372                                    (Arg (Arg'First .. SwP),
3373                                     Matching_Name
3374                                       ("COMPILE", Commands).Switches,
3375                                     Quiet => False);
3376                               end if;
3377
3378                               --  For all other cases, just search the relevant
3379                               --  command.
3380
3381                            else
3382                               Sw :=
3383                                 Matching_Name
3384                                 (Arg (Arg'First .. SwP),
3385                                  Command.Switches,
3386                                  Quiet => False);
3387                            end if;
3388
3389                            if Sw /= null then
3390                               case Sw.Translation is
3391
3392                                  when T_Direct =>
3393                                     Place_Unix_Switches (Sw.Unix_String);
3394                                     if SwP < Arg'Last
3395                                       and then Arg (SwP + 1) = '='
3396                                     then
3397                                        Put (Standard_Error,
3398                                             "qualifier options ignored: ");
3399                                        Put_Line (Standard_Error, Arg.all);
3400                                     end if;
3401
3402                                  when T_Directories =>
3403                                     if SwP + 1 > Arg'Last then
3404                                        Put (Standard_Error,
3405                                             "missing directories for: ");
3406                                        Put_Line (Standard_Error, Arg.all);
3407                                        Errors := Errors + 1;
3408
3409                                     elsif Arg (SwP + 2) /= '(' then
3410                                        SwP := SwP + 2;
3411                                        Endp := Arg'Last;
3412
3413                                     elsif Arg (Arg'Last) /= ')' then
3414
3415                                        --  Remove spaces from a comma separated
3416                                        --  list of file names and adjust
3417                                        --  control variables accordingly.
3418
3419                                        if Arg_Num < Argument_Count and then
3420                                          (Argv (Argv'Last) = ',' xor
3421                                           Argument (Arg_Num + 1)
3422                                           (Argument (Arg_Num + 1)'First) = ',')
3423                                        then
3424                                           Argv :=
3425                                             new String'(Argv.all
3426                                                         & Argument
3427                                                            (Arg_Num + 1));
3428                                           Arg_Num := Arg_Num + 1;
3429                                           Arg_Idx := Argv'First;
3430                                           Next_Arg_Idx
3431                                             := Get_Arg_End (Argv.all, Arg_Idx);
3432                                           Arg := new String'
3433                                             (Argv (Arg_Idx .. Next_Arg_Idx));
3434                                           goto Tryagain_After_Coalesce;
3435                                        end if;
3436
3437                                        Put (Standard_Error,
3438                                             "incorrectly parenthesized " &
3439                                             "or malformed argument: ");
3440                                        Put_Line (Standard_Error, Arg.all);
3441                                        Errors := Errors + 1;
3442
3443                                     else
3444                                        SwP := SwP + 3;
3445                                        Endp := Arg'Last - 1;
3446                                     end if;
3447
3448                                     while SwP <= Endp loop
3449                                        declare
3450                                           Dir_Is_Wild       : Boolean := False;
3451                                           Dir_Maybe_Is_Wild : Boolean := False;
3452                                           Dir_List : String_Access_List_Access;
3453                                        begin
3454                                           P2 := SwP;
3455
3456                                           while P2 < Endp
3457                                             and then Arg (P2 + 1) /= ','
3458                                           loop
3459
3460                                              --  A wildcard directory spec on
3461                                              --  VMS will contain either * or
3462                                              --  % or ...
3463
3464                                              if Arg (P2) = '*' then
3465                                                 Dir_Is_Wild := True;
3466
3467                                              elsif Arg (P2) = '%' then
3468                                                 Dir_Is_Wild := True;
3469
3470                                              elsif Dir_Maybe_Is_Wild
3471                                                and then Arg (P2) = '.'
3472                                                and then Arg (P2 + 1) = '.'
3473                                              then
3474                                                 Dir_Is_Wild := True;
3475                                                 Dir_Maybe_Is_Wild := False;
3476
3477                                              elsif Dir_Maybe_Is_Wild then
3478                                                 Dir_Maybe_Is_Wild := False;
3479
3480                                              elsif Arg (P2) = '.'
3481                                                and then Arg (P2 + 1) = '.'
3482                                              then
3483                                                 Dir_Maybe_Is_Wild := True;
3484
3485                                              end if;
3486
3487                                              P2 := P2 + 1;
3488                                           end loop;
3489
3490                                           if (Dir_Is_Wild) then
3491                                              Dir_List := To_Canonical_File_List
3492                                                (Arg (SwP .. P2), True);
3493
3494                                              for I in Dir_List.all'Range loop
3495                                                 Place_Unix_Switches
3496                                                   (Sw.Unix_String);
3497                                                 Place_Lower
3498                                                   (Dir_List.all (I).all);
3499                                              end loop;
3500                                           else
3501                                              Place_Unix_Switches
3502                                                (Sw.Unix_String);
3503                                              Place_Lower
3504                                                (To_Canonical_Dir_Spec
3505                                                 (Arg (SwP .. P2), False).all);
3506                                           end if;
3507
3508                                           SwP := P2 + 2;
3509                                        end;
3510                                     end loop;
3511
3512                                  when T_Directory =>
3513                                     if SwP + 1 > Arg'Last then
3514                                        Put (Standard_Error,
3515                                             "missing directory for: ");
3516                                        Put_Line (Standard_Error, Arg.all);
3517                                        Errors := Errors + 1;
3518
3519                                     else
3520                                        Place_Unix_Switches (Sw.Unix_String);
3521
3522                                        --  Some switches end in "=". No space
3523                                        --  here
3524
3525                                        if Sw.Unix_String
3526                                          (Sw.Unix_String'Last) /= '='
3527                                        then
3528                                           Place (' ');
3529                                        end if;
3530
3531                                        Place_Lower
3532                                          (To_Canonical_Dir_Spec
3533                                           (Arg (SwP + 2 .. Arg'Last),
3534                                            False).all);
3535                                     end if;
3536
3537                                  when T_File | T_No_Space_File =>
3538                                     if SwP + 1 > Arg'Last then
3539                                        Put (Standard_Error,
3540                                             "missing file for: ");
3541                                        Put_Line (Standard_Error, Arg.all);
3542                                        Errors := Errors + 1;
3543
3544                                     else
3545                                        Place_Unix_Switches (Sw.Unix_String);
3546
3547                                        --  Some switches end in "=". No space
3548                                        --  here.
3549
3550                                        if Sw.Translation = T_File
3551                                          and then Sw.Unix_String
3552                                                    (Sw.Unix_String'Last) /= '='
3553                                        then
3554                                           Place (' ');
3555                                        end if;
3556
3557                                        Place_Lower
3558                                          (To_Canonical_File_Spec
3559                                           (Arg (SwP + 2 .. Arg'Last)).all);
3560                                     end if;
3561
3562                                  when T_Numeric =>
3563                                     if
3564                                       OK_Integer (Arg (SwP + 2 .. Arg'Last))
3565                                     then
3566                                        Place_Unix_Switches (Sw.Unix_String);
3567                                        Place (Arg (SwP + 2 .. Arg'Last));
3568
3569                                     else
3570                                        Put (Standard_Error, "argument for ");
3571                                        Put (Standard_Error, Sw.Name.all);
3572                                        Put_Line
3573                                          (Standard_Error, " must be numeric");
3574                                        Errors := Errors + 1;
3575                                     end if;
3576
3577                                  when T_Alphanumplus =>
3578                                     if
3579                                       OK_Alphanumerplus
3580                                         (Arg (SwP + 2 .. Arg'Last))
3581                                     then
3582                                        Place_Unix_Switches (Sw.Unix_String);
3583                                        Place (Arg (SwP + 2 .. Arg'Last));
3584
3585                                     else
3586                                        Put (Standard_Error, "argument for ");
3587                                        Put (Standard_Error, Sw.Name.all);
3588                                        Put_Line (Standard_Error,
3589                                                  " must be alphanumeric");
3590                                        Errors := Errors + 1;
3591                                     end if;
3592
3593                                  when T_String =>
3594
3595                                     --  A String value must be extended to the
3596                                     --  end of the Argv, otherwise strings like
3597                                     --  "foo/bar" get split at the slash.
3598                                     --
3599                                     --  The begining and ending of the string
3600                                     --  are flagged with embedded nulls which
3601                                     --  are removed when building the Spawn
3602                                     --  call. Nulls are use because they won't
3603                                     --  show up in a /? output. Quotes aren't
3604                                     --  used because that would make it
3605                                     --  difficult to embed them.
3606
3607                                     Place_Unix_Switches (Sw.Unix_String);
3608                                     if Next_Arg_Idx /= Argv'Last then
3609                                        Next_Arg_Idx := Argv'Last;
3610                                        Arg := new String'
3611                                          (Argv (Arg_Idx .. Next_Arg_Idx));
3612
3613                                        SwP := Arg'First;
3614                                        while SwP < Arg'Last and then
3615                                          Arg (SwP + 1) /= '=' loop
3616                                           SwP := SwP + 1;
3617                                        end loop;
3618                                     end if;
3619                                     Place (ASCII.NUL);
3620                                     Place (Arg (SwP + 2 .. Arg'Last));
3621                                     Place (ASCII.NUL);
3622
3623                                  when T_Commands =>
3624
3625                                     --  Output -largs/-bargs/-cargs
3626
3627                                     Place (' ');
3628                                     Place (Sw.Unix_String
3629                                            (Sw.Unix_String'First ..
3630                                             Sw.Unix_String'First + 5));
3631
3632                                     --  Set source of new commands, also
3633                                     --  setting this non-null indicates that
3634                                     --  we are in the special commands mode
3635                                     --  for processing the -xargs case.
3636
3637                                     Make_Commands_Active :=
3638                                       Matching_Name
3639                                       (Sw.Unix_String
3640                                        (Sw.Unix_String'First + 7 ..
3641                                         Sw.Unix_String'Last),
3642                                        Commands);
3643
3644                                  when T_Options =>
3645                                     if SwP + 1 > Arg'Last then
3646                                        Place_Unix_Switches
3647                                          (Sw.Options.Unix_String);
3648                                        SwP := Endp + 1;
3649
3650                                     elsif Arg (SwP + 2) /= '(' then
3651                                        SwP := SwP + 2;
3652                                        Endp := Arg'Last;
3653
3654                                     elsif Arg (Arg'Last) /= ')' then
3655                                        Put
3656                                          (Standard_Error,
3657                                           "incorrectly parenthesized " &
3658                                           "argument: ");
3659                                        Put_Line (Standard_Error, Arg.all);
3660                                        Errors := Errors + 1;
3661                                        SwP := Endp + 1;
3662
3663                                     else
3664                                        SwP := SwP + 3;
3665                                        Endp := Arg'Last - 1;
3666                                     end if;
3667
3668                                     while SwP <= Endp loop
3669                                        P2 := SwP;
3670
3671                                        while P2 < Endp
3672                                          and then Arg (P2 + 1) /= ','
3673                                        loop
3674                                           P2 := P2 + 1;
3675                                        end loop;
3676
3677                                        --  Option name is in Arg (SwP .. P2)
3678
3679                                        Opt := Matching_Name (Arg (SwP .. P2),
3680                                                              Sw.Options);
3681
3682                                        if Opt /= null then
3683                                           Place_Unix_Switches
3684                                             (Opt.Unix_String);
3685                                        end if;
3686
3687                                        SwP := P2 + 2;
3688                                     end loop;
3689
3690                                  when T_Other =>
3691                                     Place_Unix_Switches
3692                                       (new String'(Sw.Unix_String.all &
3693                                                    Arg.all));
3694
3695                               end case;
3696                            end if;
3697                         end;
3698                      end if;
3699
3700                      Arg_Idx := Next_Arg_Idx + 1;
3701                   end;
3702
3703                   exit when Arg_Idx > Argv'Last;
3704
3705                end loop;
3706          end Process_Argument;
3707
3708          Arg_Num := Arg_Num + 1;
3709       end loop;
3710
3711       if Display_Command then
3712          Put (Standard_Error, "generated command -->");
3713          Put (Standard_Error, Command_List (The_Command).Unixcmd.all);
3714
3715          if Command_List (The_Command).Unixsws /= null then
3716             for J in Command_List (The_Command).Unixsws'Range loop
3717                Put (Standard_Error, " ");
3718                Put (Standard_Error,
3719                     Command_List (The_Command).Unixsws (J).all);
3720             end loop;
3721          end if;
3722
3723          Put (Standard_Error, " ");
3724          Put (Standard_Error, String (Buffer.Table (1 .. Buffer.Last)));
3725          Put (Standard_Error, "<--");
3726          New_Line (Standard_Error);
3727          raise Normal_Exit;
3728       end if;
3729
3730       --  Gross error checking that the number of parameters is correct.
3731       --  Not applicable to Unlimited_Files parameters.
3732
3733       if (Param_Count = Command.Params'Length - 1
3734             and then Command.Params (Param_Count + 1) = Unlimited_Files)
3735         or else Param_Count <= Command.Params'Length
3736       then
3737          null;
3738
3739       else
3740          Put_Line (Standard_Error,
3741                    "Parameter count of "
3742                    & Integer'Image (Param_Count)
3743                    & " not equal to expected "
3744                    & Integer'Image (Command.Params'Length));
3745          Put (Standard_Error, "usage: ");
3746          Put_Line (Standard_Error, Command.Usage.all);
3747          Errors := Errors + 1;
3748       end if;
3749
3750       if Errors > 0 then
3751          raise Error_Exit;
3752       else
3753          --  Prepare arguments for a call to spawn, filtering out
3754          --  embedded nulls place there to delineate strings.
3755
3756          declare
3757             P1, P2     : Natural;
3758             Inside_Nul : Boolean := False;
3759             Arg        : String (1 .. 1024);
3760             Arg_Ctr    : Natural;
3761
3762          begin
3763             P1 := 1;
3764
3765             while P1 <= Buffer.Last and then Buffer.Table (P1) = ' ' loop
3766                P1 := P1 + 1;
3767             end loop;
3768
3769             Arg_Ctr := 1;
3770             Arg (Arg_Ctr) := Buffer.Table (P1);
3771
3772             while P1 <= Buffer.Last loop
3773
3774                if Buffer.Table (P1) = ASCII.NUL then
3775                   if Inside_Nul then
3776                      Inside_Nul := False;
3777                   else
3778                      Inside_Nul := True;
3779                   end if;
3780                end if;
3781
3782                if Buffer.Table (P1) = ' ' and then not Inside_Nul then
3783                   P1 := P1 + 1;
3784                   Arg_Ctr := Arg_Ctr + 1;
3785                   Arg (Arg_Ctr) := Buffer.Table (P1);
3786
3787                else
3788                   Last_Switches.Increment_Last;
3789                   P2 := P1;
3790
3791                   while P2 < Buffer.Last
3792                     and then (Buffer.Table (P2 + 1) /= ' ' or else
3793                               Inside_Nul)
3794                   loop
3795                      P2 := P2 + 1;
3796                      Arg_Ctr := Arg_Ctr + 1;
3797                      Arg (Arg_Ctr) := Buffer.Table (P2);
3798                      if Buffer.Table (P2) = ASCII.NUL then
3799                         Arg_Ctr := Arg_Ctr - 1;
3800                         if Inside_Nul then
3801                            Inside_Nul := False;
3802                         else
3803                            Inside_Nul := True;
3804                         end if;
3805                      end if;
3806                   end loop;
3807
3808                   Last_Switches.Table (Last_Switches.Last) :=
3809                     new String'(String (Arg (1 .. Arg_Ctr)));
3810                   P1 := P2 + 2;
3811                   Arg_Ctr := 1;
3812                   Arg (Arg_Ctr) := Buffer.Table (P1);
3813                end if;
3814             end loop;
3815          end;
3816       end if;
3817    end VMS_Conversion;
3818
3819    -------------------------------------
3820    -- Start of processing for GNATCmd --
3821    -------------------------------------
3822
3823 begin
3824    --  Initializations
3825
3826    Namet.Initialize;
3827    Csets.Initialize;
3828
3829    Snames.Initialize;
3830
3831    Prj.Initialize;
3832
3833    Last_Switches.Init;
3834    Last_Switches.Set_Last (0);
3835
3836    First_Switches.Init;
3837    First_Switches.Set_Last (0);
3838
3839    --  If on VMS, or if VMS emulation is on, convert VMS style /qualifiers,
3840    --  filenames and pathnames to Unix style.
3841
3842    if Hostparm.OpenVMS
3843      or else To_Lower (Getenv ("EMULATE_VMS").all) = "true"
3844    then
3845       VMS_Conversion (The_Command);
3846
3847    --  If not on VMS, scan the command line directly
3848
3849    else
3850       if Argument_Count = 0 then
3851          Non_VMS_Usage;
3852          return;
3853       else
3854          begin
3855             if Argument_Count > 1 and then Argument (1) = "-v" then
3856                Opt.Verbose_Mode := True;
3857                Command_Arg := 2;
3858             end if;
3859
3860             The_Command := Real_Command_Type'Value (Argument (Command_Arg));
3861
3862             if Command_List (The_Command).VMS_Only then
3863                Non_VMS_Usage;
3864                Fail ("Command """ & Command_List (The_Command).Cname.all &
3865                      """ can only be used on VMS");
3866             end if;
3867          exception
3868             when Constraint_Error =>
3869
3870                --  Check if it is an alternate command
3871                declare
3872                   Alternate : Alternate_Command;
3873
3874                begin
3875                   Alternate := Alternate_Command'Value
3876                                               (Argument (Command_Arg));
3877                   The_Command := Corresponding_To (Alternate);
3878
3879                exception
3880                   when Constraint_Error =>
3881                      Non_VMS_Usage;
3882                      Fail ("Unknown command: " & Argument (Command_Arg));
3883                end;
3884          end;
3885
3886          for Arg in Command_Arg + 1 .. Argument_Count loop
3887             Last_Switches.Increment_Last;
3888             Last_Switches.Table (Last_Switches.Last) :=
3889               new String'(Argument (Arg));
3890          end loop;
3891       end if;
3892    end if;
3893
3894    declare
3895       Program : constant String :=
3896         Program_Name (Command_List (The_Command).Unixcmd.all).all;
3897
3898       Exec_Path : String_Access;
3899
3900    begin
3901       --  Locate the executable for the command
3902
3903       Exec_Path := Locate_Exec_On_Path (Program);
3904
3905       if Exec_Path = null then
3906          Put_Line (Standard_Error, "Couldn't locate " & Program);
3907          raise Error_Exit;
3908       end if;
3909
3910       --  If there are switches for the executable, put them as first switches
3911
3912       if Command_List (The_Command).Unixsws /= null then
3913          for J in Command_List (The_Command).Unixsws'Range loop
3914             First_Switches.Increment_Last;
3915             First_Switches.Table (First_Switches.Last) :=
3916               Command_List (The_Command).Unixsws (J);
3917          end loop;
3918       end if;
3919
3920       --  For BIND, FIND, LINK, LIST and XREF, look for project file related
3921       --  switches.
3922
3923       if The_Command = Bind
3924         or else The_Command = Find
3925         or else The_Command = Link
3926         or else The_Command = List
3927         or else The_Command = Xref
3928       then
3929          case The_Command is
3930             when Bind =>
3931                Tool_Package_Name := Name_Binder;
3932             when Find =>
3933                Tool_Package_Name := Name_Finder;
3934             when Link =>
3935                Tool_Package_Name := Name_Linker;
3936             when List =>
3937                Tool_Package_Name := Name_Gnatls;
3938             when Xref =>
3939                Tool_Package_Name := Name_Cross_Reference;
3940             when others =>
3941                null;
3942          end case;
3943
3944          declare
3945             Arg_Num : Positive := 1;
3946             Argv    : String_Access;
3947
3948             procedure Remove_Switch (Num : Positive);
3949             --  Remove a project related switch from table Last_Switches
3950
3951             -------------------
3952             -- Remove_Switch --
3953             -------------------
3954
3955             procedure Remove_Switch (Num : Positive) is
3956             begin
3957                Last_Switches.Table (Num .. Last_Switches.Last - 1) :=
3958                  Last_Switches.Table (Num + 1 .. Last_Switches.Last);
3959                Last_Switches.Decrement_Last;
3960             end Remove_Switch;
3961
3962          --  Start of processing for ??? (need block name here)
3963
3964          begin
3965             while Arg_Num <= Last_Switches.Last loop
3966                Argv := Last_Switches.Table (Arg_Num);
3967
3968                if Argv (Argv'First) = '-' then
3969                   if Argv'Length = 1 then
3970                      Fail ("switch character cannot be followed by a blank");
3971                   end if;
3972
3973                   --  The two style project files (-p and -P) cannot be used
3974                   --  together
3975
3976                   if (The_Command = Find or else The_Command = Xref)
3977                     and then Argv (2) = 'p'
3978                   then
3979                      Old_Project_File_Used := True;
3980                      if Project_File /= null then
3981                         Fail ("-P and -p cannot be used together");
3982                      end if;
3983                   end if;
3984
3985                   --  -vPx  Specify verbosity while parsing project files
3986
3987                   if Argv'Length = 4
3988                     and then Argv (Argv'First + 1 .. Argv'First + 2) = "vP"
3989                   then
3990                      case Argv (Argv'Last) is
3991                         when '0' =>
3992                            Current_Verbosity := Prj.Default;
3993                         when '1' =>
3994                            Current_Verbosity := Prj.Medium;
3995                         when '2' =>
3996                            Current_Verbosity := Prj.High;
3997                         when others =>
3998                            Fail ("Invalid switch: " & Argv.all);
3999                      end case;
4000
4001                      Remove_Switch (Arg_Num);
4002
4003                   --  -Pproject_file  Specify project file to be used
4004
4005                   elsif Argv'Length >= 3
4006                     and then Argv (Argv'First + 1) = 'P'
4007                   then
4008
4009                      --  Only one -P switch can be used
4010
4011                      if Project_File /= null then
4012                         Fail (Argv.all &
4013                               ": second project file forbidden (first is """ &
4014                               Project_File.all & """)");
4015
4016                      --  The two style project files (-p and -P) cannot be
4017                      --  used together.
4018
4019                      elsif Old_Project_File_Used then
4020                         Fail ("-p and -P cannot be used together");
4021
4022                      else
4023                         Project_File :=
4024                           new String'(Argv (Argv'First + 2 .. Argv'Last));
4025                      end if;
4026
4027                      Remove_Switch (Arg_Num);
4028
4029                   --  -Xexternal=value Specify an external reference to be
4030                   --                   used in project files
4031
4032                   elsif Argv'Length >= 5
4033                     and then Argv (Argv'First + 1) = 'X'
4034                   then
4035                      declare
4036                         Equal_Pos : constant Natural :=
4037                           Index ('=', Argv (Argv'First + 2 .. Argv'Last));
4038                      begin
4039                         if Equal_Pos >= Argv'First + 3 and then
4040                           Equal_Pos /= Argv'Last then
4041                            Add (External_Name =>
4042                                   Argv (Argv'First + 2 .. Equal_Pos - 1),
4043                                 Value => Argv (Equal_Pos + 1 .. Argv'Last));
4044                         else
4045                            Fail (Argv.all &
4046                                  " is not a valid external assignment.");
4047                         end if;
4048                      end;
4049
4050                      Remove_Switch (Arg_Num);
4051
4052                   else
4053                      Arg_Num := Arg_Num + 1;
4054                   end if;
4055
4056                else
4057                   Arg_Num := Arg_Num + 1;
4058                end if;
4059             end loop;
4060          end;
4061       end if;
4062
4063       --  If there is a project file specified, parse it, get the switches
4064       --  for the tool and setup PATH environment variables.
4065
4066       if Project_File /= null then
4067          Prj.Pars.Set_Verbosity (To => Current_Verbosity);
4068
4069          Prj.Pars.Parse
4070            (Project           => Project,
4071             Project_File_Name => Project_File.all);
4072
4073          if Project = Prj.No_Project then
4074             Fail ("""" & Project_File.all & """ processing failed");
4075          end if;
4076
4077          --  Check if a package with the name of the tool is in the project
4078          --  file and if there is one, get the switches, if any, and scan them.
4079
4080          declare
4081             Data : Prj.Project_Data := Prj.Projects.Table (Project);
4082             Pkg  : Prj.Package_Id :=
4083                      Prj.Util.Value_Of
4084                        (Name        => Tool_Package_Name,
4085                         In_Packages => Data.Decl.Packages);
4086
4087             Element : Package_Element;
4088
4089             Default_Switches_Array : Array_Element_Id;
4090
4091             The_Switches : Prj.Variable_Value;
4092             Current      : Prj.String_List_Id;
4093             The_String   : String_Element;
4094
4095          begin
4096             if Pkg /= No_Package then
4097                Element := Packages.Table (Pkg);
4098
4099                --  Packages Gnatls has a single attribute Switches, that is
4100                --  not an associative array.
4101
4102                if The_Command = List then
4103                   The_Switches :=
4104                     Prj.Util.Value_Of
4105                     (Variable_Name => Snames.Name_Switches,
4106                      In_Variables => Element.Decl.Attributes);
4107
4108                --  Packages Binder (for gnatbind), Cross_Reference (for
4109                --  gnatxref), Linker (for gnatlink) and Finder
4110                --  (for gnatfind) have an attributed Default_Switches,
4111                --  an associative array, indexed by the name of the
4112                --  programming language.
4113                else
4114                   Default_Switches_Array :=
4115                     Prj.Util.Value_Of
4116                     (Name => Name_Default_Switches,
4117                      In_Arrays => Packages.Table (Pkg).Decl.Arrays);
4118                   The_Switches := Prj.Util.Value_Of
4119                     (Index => Name_Ada,
4120                      In_Array => Default_Switches_Array);
4121
4122                end if;
4123
4124                --  If there are switches specified in the package of the
4125                --  project file corresponding to the tool, scan them.
4126
4127                case The_Switches.Kind is
4128                   when Prj.Undefined =>
4129                      null;
4130
4131                   when Prj.Single =>
4132                      if String_Length (The_Switches.Value) > 0 then
4133                         String_To_Name_Buffer (The_Switches.Value);
4134                         First_Switches.Increment_Last;
4135                         First_Switches.Table (First_Switches.Last) :=
4136                           new String'(Name_Buffer (1 .. Name_Len));
4137                      end if;
4138
4139                   when Prj.List =>
4140                      Current := The_Switches.Values;
4141                      while Current /= Prj.Nil_String loop
4142                         The_String := String_Elements.Table (Current);
4143
4144                         if String_Length (The_String.Value) > 0 then
4145                            String_To_Name_Buffer (The_String.Value);
4146                            First_Switches.Increment_Last;
4147                            First_Switches.Table (First_Switches.Last) :=
4148                              new String'(Name_Buffer (1 .. Name_Len));
4149                         end if;
4150
4151                         Current := The_String.Next;
4152                      end loop;
4153                end case;
4154             end if;
4155          end;
4156
4157          --  Set up the environment variables ADA_INCLUDE_PATH and
4158          --  ADA_OBJECTS_PATH.
4159
4160          Setenv
4161            (Name  => Ada_Include_Path,
4162             Value => Prj.Env.Ada_Include_Path (Project).all);
4163          Setenv
4164            (Name  => Ada_Objects_Path,
4165             Value => Prj.Env.Ada_Objects_Path
4166             (Project, Including_Libraries => False).all);
4167
4168          if The_Command = Bind or else The_Command = Link then
4169             Change_Dir
4170               (Get_Name_String
4171                  (Projects.Table (Project).Object_Directory));
4172          end if;
4173
4174          if The_Command = Link then
4175
4176             --  Add the default search directories, to be able to find
4177             --  libgnat in call to MLib.Utl.Lib_Directory.
4178
4179             Add_Default_Search_Dirs;
4180
4181             declare
4182                There_Are_Libraries  : Boolean := False;
4183
4184             begin
4185                --  Check if there are library project files
4186
4187                if MLib.Tgt.Libraries_Are_Supported then
4188                   Set_Libraries (Project, There_Are_Libraries);
4189                end if;
4190
4191                --  If there are, add the necessary additional switches
4192
4193                if There_Are_Libraries then
4194
4195                   --  Add -L<lib_dir> -lgnarl -lgnat -Wl,-rpath,<lib_dir>
4196
4197                   Last_Switches.Increment_Last;
4198                   Last_Switches.Table (Last_Switches.Last) :=
4199                     new String'("-L" & MLib.Utl.Lib_Directory);
4200                   Last_Switches.Increment_Last;
4201                   Last_Switches.Table (Last_Switches.Last) :=
4202                     new String'("-lgnarl");
4203                   Last_Switches.Increment_Last;
4204                   Last_Switches.Table (Last_Switches.Last) :=
4205                     new String'("-lgnat");
4206
4207                   declare
4208                      Option : constant String_Access :=
4209                        MLib.Tgt.Linker_Library_Path_Option
4210                        (MLib.Utl.Lib_Directory);
4211
4212                   begin
4213                      if Option /= null then
4214                         Last_Switches.Increment_Last;
4215                         Last_Switches.Table (Last_Switches.Last) :=
4216                           Option;
4217                      end if;
4218                   end;
4219                end if;
4220             end;
4221          end if;
4222       end if;
4223
4224       --  Gather all the arguments and invoke the executable
4225
4226       declare
4227          The_Args : Argument_List
4228            (1 .. First_Switches.Last + Last_Switches.Last);
4229          Arg_Num : Natural := 0;
4230       begin
4231          for J in 1 .. First_Switches.Last loop
4232             Arg_Num := Arg_Num + 1;
4233             The_Args (Arg_Num) := First_Switches.Table (J);
4234          end loop;
4235
4236          for J in 1 .. Last_Switches.Last loop
4237             Arg_Num := Arg_Num + 1;
4238             The_Args (Arg_Num) := Last_Switches.Table (J);
4239          end loop;
4240
4241          if Opt.Verbose_Mode then
4242             Output.Write_Str (Exec_Path.all);
4243
4244             for Arg in The_Args'Range loop
4245                Output.Write_Char (' ');
4246                Output.Write_Str (The_Args (Arg).all);
4247             end loop;
4248
4249             Output.Write_Eol;
4250          end if;
4251
4252          My_Exit_Status
4253            := Exit_Status (Spawn (Exec_Path.all, The_Args));
4254          raise Normal_Exit;
4255       end;
4256    end;
4257
4258 exception
4259    when Error_Exit =>
4260       Set_Exit_Status (Failure);
4261
4262    when Normal_Exit =>
4263       Set_Exit_Status (My_Exit_Status);
4264
4265 end GNATCmd;