OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc1/] [gcc/] [ada/] [vms_conv.adb] - Blame information for rev 513

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 281 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                         GNAT COMPILER COMPONENTS                         --
4
--                                                                          --
5
--                            V M S _ C O N V                               --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--          Copyright (C) 1996-2009, Free Software Foundation, Inc.         --
10
--                                                                          --
11
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17
-- for  more details.  You should have  received  a copy of the GNU General --
18
-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19
-- http://www.gnu.org/licenses for a complete copy of the license.          --
20
--                                                                          --
21
-- GNAT was originally developed  by the GNAT team at  New York University. --
22
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
23
--                                                                          --
24
------------------------------------------------------------------------------
25
 
26
with Gnatvsn;  use Gnatvsn;
27
with Hostparm;
28
with Opt;
29
with Osint;    use Osint;
30
with Targparm; use Targparm;
31
 
32
with Ada.Characters.Handling; use Ada.Characters.Handling;
33
with Ada.Command_Line;        use Ada.Command_Line;
34
with Ada.Text_IO;             use Ada.Text_IO;
35
 
36
package body VMS_Conv is
37
 
38
   -------------------------
39
   -- Internal Structures --
40
   -------------------------
41
 
42
   --  The switches and commands are defined by strings in the previous
43
   --  section so that they are easy to modify, but internally, they are
44
   --  kept in a more conveniently accessible form described in this
45
   --  section.
46
 
47
   --  Commands, command qualifiers and options have a similar common format
48
   --  so that searching for matching names can be done in a common manner.
49
 
50
   type Item_Id is (Id_Command, Id_Switch, Id_Option);
51
 
52
   type Translation_Type is
53
     (
54
      T_Direct,
55
      --  A qualifier with no options.
56
      --  Example: GNAT MAKE /VERBOSE
57
 
58
      T_Directories,
59
      --  A qualifier followed by a list of directories
60
      --  Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
61
 
62
      T_Directory,
63
      --  A qualifier followed by one directory
64
      --  Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
65
 
66
      T_File,
67
      --  A qualifier followed by a filename
68
      --  Example: GNAT LINK /EXECUTABLE=FOO.EXE
69
 
70
      T_No_Space_File,
71
      --  A qualifier followed by a filename
72
      --  Example: GNAT MAKE /PROJECT_FILE=PRJ.GPR
73
 
74
      T_Numeric,
75
      --  A qualifier followed by a numeric value.
76
      --  Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
77
 
78
      T_String,
79
      --  A qualifier followed by a quoted string. Only used by
80
      --  /IDENTIFICATION qualifier.
81
      --  Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
82
 
83
      T_Options,
84
      --  A qualifier followed by a list of options.
85
      --  Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
86
 
87
      T_Commands,
88
      --  A qualifier followed by a list. Only used for
89
      --  MAKE /COMPILER_QUALIFIERS /BINDER_QUALIFIERS /LINKER_QUALIFIERS
90
      --  (gnatmake -cargs -bargs -largs )
91
      --  Example: GNAT MAKE ... /LINKER_QUALIFIERS /VERBOSE FOOBAR.OBJ
92
 
93
      T_Other,
94
      --  A qualifier passed directly to the linker. Only used
95
      --  for LINK and SHARED if no other match is found.
96
      --  Example: GNAT LINK FOO.ALI /SYSSHR
97
 
98
      T_Alphanumplus
99
      --  A qualifier followed by a legal linker symbol prefix. Only used
100
      --  for BIND /BUILD_LIBRARY (gnatbind -Lxyz).
101
      --  Example: GNAT BIND /BUILD_LIBRARY=foobar
102
      );
103
 
104
   type Item (Id : Item_Id);
105
   type Item_Ptr is access all Item;
106
 
107
   type Item (Id : Item_Id) is record
108
      Name : String_Ptr;
109
      --  Name of the command, switch (with slash) or option
110
 
111
      Next : Item_Ptr;
112
      --  Pointer to next item on list, always has the same Id value
113
 
114
      Command : Command_Type := Undefined;
115
 
116
      Unix_String : String_Ptr := null;
117
      --  Corresponding Unix string. For a command, this is the unix command
118
      --  name and possible default switches. For a switch or option it is
119
      --  the unix switch string.
120
 
121
      case Id is
122
 
123
         when Id_Command =>
124
 
125
            Switches : Item_Ptr;
126
            --  Pointer to list of switch items for the command, linked
127
            --  through the Next fields with null terminating the list.
128
 
129
            Usage : String_Ptr;
130
            --  Usage information, used only for errors and the default
131
            --  list of commands output.
132
 
133
            Params : Parameter_Ref;
134
            --  Array of parameters
135
 
136
            Defext : String (1 .. 3);
137
            --  Default extension. If non-blank, then this extension is
138
            --  supplied by default as the extension for any file parameter
139
            --  which does not have an extension already.
140
 
141
         when Id_Switch =>
142
 
143
            Translation : Translation_Type;
144
            --  Type of switch translation. For all cases, except Options,
145
            --  this is the only field needed, since the Unix translation
146
            --  is found in Unix_String.
147
 
148
            Options : Item_Ptr;
149
            --  For the Options case, this field is set to point to a list
150
            --  of options item (for this case Unix_String is null in the
151
            --  main switch item). The end of the list is marked by null.
152
 
153
         when Id_Option =>
154
 
155
            null;
156
            --  No special fields needed, since Name and Unix_String are
157
            --  sufficient to completely described an option.
158
 
159
      end case;
160
   end record;
161
 
162
   subtype Command_Item is Item (Id_Command);
163
   subtype Switch_Item  is Item (Id_Switch);
164
   subtype Option_Item  is Item (Id_Option);
165
 
166
   Keep_Temps_Option : constant Item_Ptr :=
167
                         new Item'
168
                           (Id          => Id_Option,
169
                            Name        =>
170
                              new String'("/KEEP_TEMPORARY_FILES"),
171
                            Next        => null,
172
                            Command     => Undefined,
173
                            Unix_String => null);
174
 
175
   Param_Count : Natural := 0;
176
   --  Number of parameter arguments so far
177
 
178
   Arg_Num : Natural;
179
   --  Argument number
180
 
181
   Arg_File : Ada.Text_IO.File_Type;
182
   --  A file where arguments are read from
183
 
184
   Commands : Item_Ptr;
185
   --  Pointer to head of list of command items, one for each command, with
186
   --  the end of the list marked by a null pointer.
187
 
188
   Last_Command : Item_Ptr;
189
   --  Pointer to last item in Commands list
190
 
191
   Command : Item_Ptr;
192
   --  Pointer to command item for current command
193
 
194
   Make_Commands_Active : Item_Ptr := null;
195
   --  Set to point to Command entry for COMPILE, BIND, or LINK as appropriate
196
   --  if a COMMANDS_TRANSLATION switch has been encountered while processing
197
   --  a MAKE Command.
198
 
199
   Output_File_Expected : Boolean := False;
200
   --  True for GNAT LINK after -o switch, so that the ".ali" extension is
201
   --  not added to the executable file name.
202
 
203
   package Buffer is new Table.Table
204
     (Table_Component_Type => Character,
205
      Table_Index_Type     => Integer,
206
      Table_Low_Bound      => 1,
207
      Table_Initial        => 4096,
208
      Table_Increment      => 100,
209
      Table_Name           => "Buffer");
210
   --  Table to store the command to be used
211
 
212
   package Cargs_Buffer is new Table.Table
213
     (Table_Component_Type => Character,
214
      Table_Index_Type     => Integer,
215
      Table_Low_Bound      => 1,
216
      Table_Initial        => 4096,
217
      Table_Increment      => 100,
218
      Table_Name           => "Cargs_Buffer");
219
   --  Table to store the compiler switches for GNAT COMPILE
220
 
221
   Cargs : Boolean := False;
222
   --  When True, commands should go to Cargs_Buffer instead of Buffer table
223
 
224
   function Init_Object_Dirs return Argument_List;
225
   --  Get the list of the object directories
226
 
227
   function Invert_Sense (S : String) return VMS_Data.String_Ptr;
228
   --  Given a unix switch string S, computes the inverse (adding or
229
   --  removing ! characters as required), and returns a pointer to
230
   --  the allocated result on the heap.
231
 
232
   function Is_Extensionless (F : String) return Boolean;
233
   --  Returns true if the filename has no extension
234
 
235
   function Match (S1, S2 : String) return Boolean;
236
   --  Determines whether S1 and S2 match (this is a case insensitive match)
237
 
238
   function Match_Prefix (S1, S2 : String) return Boolean;
239
   --  Determines whether S1 matches a prefix of S2. This is also a case
240
   --  insensitive match (for example Match ("AB","abc") is True).
241
 
242
   function Matching_Name
243
     (S     : String;
244
      Itm   : Item_Ptr;
245
      Quiet : Boolean := False) return Item_Ptr;
246
   --  Determines if the item list headed by Itm and threaded through the
247
   --  Next fields (with null marking the end of the list), contains an
248
   --  entry that uniquely matches the given string. The match is case
249
   --  insensitive and permits unique abbreviation. If the match succeeds,
250
   --  then a pointer to the matching item is returned. Otherwise, an
251
   --  appropriate error message is written. Note that the discriminant
252
   --  of Itm is used to determine the appropriate form of this message.
253
   --  Quiet is normally False as shown, if it is set to True, then no
254
   --  error message is generated in a not found situation (null is still
255
   --  returned to indicate the not-found situation).
256
 
257
   function OK_Alphanumerplus (S : String) return Boolean;
258
   --  Checks that S is a string of alphanumeric characters,
259
   --  returning True if all alphanumeric characters,
260
   --  False if empty or a non-alphanumeric character is present.
261
 
262
   function OK_Integer (S : String) return Boolean;
263
   --  Checks that S is a string of digits, returning True if all digits,
264
   --  False if empty or a non-digit is present.
265
 
266
   procedure Place (C : Character);
267
   --  Place a single character in the buffer, updating Ptr
268
 
269
   procedure Place (S : String);
270
   --  Place a string character in the buffer, updating Ptr
271
 
272
   procedure Place_Lower (S : String);
273
   --  Place string in buffer, forcing letters to lower case, updating Ptr
274
 
275
   procedure Place_Unix_Switches (S : VMS_Data.String_Ptr);
276
   --  Given a unix switch string, place corresponding switches in Buffer,
277
   --  updating Ptr appropriately. Note that in the case of use of ! the
278
   --  result may be to remove a previously placed switch.
279
 
280
   procedure Preprocess_Command_Data;
281
   --  Preprocess the string form of the command and options list into the
282
   --  internal form.
283
 
284
   procedure Process_Argument (The_Command : in out Command_Type);
285
   --  Process one argument from the command line, or one line from
286
   --  from a command line file. For the first call, set The_Command.
287
 
288
   procedure Process_Buffer (S : String);
289
   --  Process the characters in the Buffer table or the Cargs_Buffer table
290
   --  to convert these into arguments.
291
 
292
   procedure Validate_Command_Or_Option (N : VMS_Data.String_Ptr);
293
   --  Check that N is a valid command or option name, i.e. that it is of the
294
   --  form of an Ada identifier with upper case letters and underscores.
295
 
296
   procedure Validate_Unix_Switch (S : VMS_Data.String_Ptr);
297
   --  Check that S is a valid switch string as described in the syntax for
298
   --  the switch table item UNIX_SWITCH or else begins with a backquote.
299
 
300
   ----------------------
301
   -- Init_Object_Dirs --
302
   ----------------------
303
 
304
   function Init_Object_Dirs return Argument_List is
305
      Object_Dirs     : Integer;
306
      Object_Dir      : Argument_List (1 .. 256);
307
      Object_Dir_Name : String_Access;
308
 
309
   begin
310
      Object_Dirs := 0;
311
      Object_Dir_Name := new String'(Object_Dir_Default_Prefix);
312
      Get_Next_Dir_In_Path_Init (Object_Dir_Name);
313
 
314
      loop
315
         declare
316
            Dir : constant String_Access :=
317
                    String_Access (Get_Next_Dir_In_Path (Object_Dir_Name));
318
         begin
319
            exit when Dir = null;
320
            Object_Dirs := Object_Dirs + 1;
321
            Object_Dir (Object_Dirs) :=
322
              new String'("-L" &
323
                          To_Canonical_Dir_Spec
324
                          (To_Host_Dir_Spec
325
                           (Normalize_Directory_Name (Dir.all).all,
326
                            True).all, True).all);
327
         end;
328
      end loop;
329
 
330
      Object_Dirs := Object_Dirs + 1;
331
      Object_Dir (Object_Dirs) := new String'("-lgnat");
332
 
333
      if OpenVMS_On_Target then
334
         Object_Dirs := Object_Dirs + 1;
335
         Object_Dir (Object_Dirs) := new String'("-ldecgnat");
336
      end if;
337
 
338
      return Object_Dir (1 .. Object_Dirs);
339
   end Init_Object_Dirs;
340
 
341
   ----------------
342
   -- Initialize --
343
   ----------------
344
 
345
   procedure Initialize is
346
   begin
347
      Command_List :=
348
        (Bind =>
349
           (Cname    => new S'("BIND"),
350
            Usage    => new S'("GNAT BIND file[.ali] /qualifiers"),
351
            VMS_Only => False,
352
            Unixcmd  => new S'("gnatbind"),
353
            Unixsws  => null,
354
            Switches => Bind_Switches'Access,
355
            Params   => new Parameter_Array'(1 => Unlimited_Files),
356
            Defext   => "ali"),
357
 
358
         Chop =>
359
           (Cname    => new S'("CHOP"),
360
            Usage    => new S'("GNAT CHOP file [directory] /qualifiers"),
361
            VMS_Only => False,
362
            Unixcmd  => new S'("gnatchop"),
363
            Unixsws  => null,
364
            Switches => Chop_Switches'Access,
365
            Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
366
            Defext   => "   "),
367
 
368
         Clean =>
369
           (Cname    => new S'("CLEAN"),
370
            Usage    => new S'("GNAT CLEAN /qualifiers files"),
371
            VMS_Only => False,
372
            Unixcmd  => new S'("gnatclean"),
373
            Unixsws  => null,
374
            Switches => Clean_Switches'Access,
375
            Params   => new Parameter_Array'(1 => File),
376
            Defext   => "   "),
377
 
378
         Compile =>
379
           (Cname    => new S'("COMPILE"),
380
            Usage    => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
381
            VMS_Only => False,
382
            Unixcmd  => new S'("gnatmake"),
383
            Unixsws  => new Argument_List'(1 => new String'("-f"),
384
                                           2 => new String'("-u"),
385
                                           3 => new String'("-c")),
386
            Switches => GCC_Switches'Access,
387
            Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
388
            Defext   => "   "),
389
 
390
         Check =>
391
           (Cname    => new S'("CHECK"),
392
            Usage    => new S'("GNAT CHECK name /qualifiers"),
393
            VMS_Only => False,
394
            Unixcmd  => new S'("gnatcheck"),
395
            Unixsws  => null,
396
            Switches => Check_Switches'Access,
397
            Params   => new Parameter_Array'(1 => Unlimited_Files),
398
            Defext   => "   "),
399
 
400
         Sync =>
401
           (Cname    => new S'("SYNC"),
402
            Usage    => new S'("GNAT SYNC name /qualifiers"),
403
            VMS_Only => False,
404
            Unixcmd  => new S'("gnatsync"),
405
            Unixsws  => null,
406
            Switches => Sync_Switches'Access,
407
            Params   => new Parameter_Array'(1 => Unlimited_Files),
408
            Defext   => "   "),
409
 
410
         Elim =>
411
           (Cname    => new S'("ELIM"),
412
            Usage    => new S'("GNAT ELIM name /qualifiers"),
413
            VMS_Only => False,
414
            Unixcmd  => new S'("gnatelim"),
415
            Unixsws  => null,
416
            Switches => Elim_Switches'Access,
417
            Params   => new Parameter_Array'(1 => Other_As_Is),
418
            Defext   => "ali"),
419
 
420
         Find =>
421
           (Cname    => new S'("FIND"),
422
            Usage    => new S'("GNAT FIND pattern[:sourcefile[:line"
423
                               & "[:column]]] filespec[,...] /qualifiers"),
424
            VMS_Only => False,
425
            Unixcmd  => new S'("gnatfind"),
426
            Unixsws  => null,
427
            Switches => Find_Switches'Access,
428
            Params   => new Parameter_Array'(1 => Other_As_Is,
429
                                             2 => Files_Or_Wildcard),
430
            Defext   => "ali"),
431
 
432
         Krunch =>
433
           (Cname    => new S'("KRUNCH"),
434
            Usage    => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
435
            VMS_Only => False,
436
            Unixcmd  => new S'("gnatkr"),
437
            Unixsws  => null,
438
            Switches => Krunch_Switches'Access,
439
            Params   => new Parameter_Array'(1 => File),
440
            Defext   => "   "),
441
 
442
         Link =>
443
           (Cname    => new S'("LINK"),
444
            Usage    => new S'("GNAT LINK file[.ali]"
445
                               & " [extra obj_&_lib_&_exe_&_opt files]"
446
                               & " /qualifiers"),
447
            VMS_Only => False,
448
            Unixcmd  => new S'("gnatlink"),
449
            Unixsws  => null,
450
            Switches => Link_Switches'Access,
451
            Params   => new Parameter_Array'(1 => Unlimited_Files),
452
            Defext   => "ali"),
453
 
454
         List =>
455
           (Cname    => new S'("LIST"),
456
            Usage    => new S'("GNAT LIST /qualifiers object_or_ali_file"),
457
            VMS_Only => False,
458
            Unixcmd  => new S'("gnatls"),
459
            Unixsws  => null,
460
            Switches => List_Switches'Access,
461
            Params   => new Parameter_Array'(1 => Unlimited_Files),
462
            Defext   => "ali"),
463
 
464
         Make =>
465
           (Cname    => new S'("MAKE"),
466
            Usage    => new S'("GNAT MAKE file(s) /qualifiers (includes "
467
                               & "COMPILE /qualifiers)"),
468
            VMS_Only => False,
469
            Unixcmd  => new S'("gnatmake"),
470
            Unixsws  => null,
471
            Switches => Make_Switches'Access,
472
            Params   => new Parameter_Array'(1 => Unlimited_Files),
473
            Defext   => "   "),
474
 
475
         Metric =>
476
           (Cname    => new S'("METRIC"),
477
            Usage    => new S'("GNAT METRIC /qualifiers source_file"),
478
            VMS_Only => False,
479
            Unixcmd  => new S'("gnatmetric"),
480
            Unixsws  => null,
481
            Switches => Metric_Switches'Access,
482
            Params   => new Parameter_Array'(1 => Unlimited_Files),
483
            Defext   => "   "),
484
 
485
         Name =>
486
           (Cname    => new S'("NAME"),
487
            Usage    => new S'("GNAT NAME /qualifiers naming-pattern "
488
                               & "[naming-patterns]"),
489
            VMS_Only => False,
490
            Unixcmd  => new S'("gnatname"),
491
            Unixsws  => null,
492
            Switches => Name_Switches'Access,
493
            Params   => new Parameter_Array'(1 => Unlimited_As_Is),
494
            Defext   => "   "),
495
 
496
         Preprocess =>
497
           (Cname    => new S'("PREPROCESS"),
498
            Usage    =>
499
              new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
500
            VMS_Only => False,
501
            Unixcmd  => new S'("gnatprep"),
502
            Unixsws  => null,
503
            Switches => Prep_Switches'Access,
504
            Params   => new Parameter_Array'(1 .. 3 => File),
505
            Defext   => "   "),
506
 
507
         Pretty =>
508
           (Cname    => new S'("PRETTY"),
509
            Usage    => new S'("GNAT PRETTY /qualifiers source_file"),
510
            VMS_Only => False,
511
            Unixcmd  => new S'("gnatpp"),
512
            Unixsws  => null,
513
            Switches => Pretty_Switches'Access,
514
            Params   => new Parameter_Array'(1 => Unlimited_Files),
515
            Defext   => "   "),
516
 
517
         Shared =>
518
           (Cname    => new S'("SHARED"),
519
            Usage    => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt"
520
                               & "files] /qualifiers"),
521
            VMS_Only => True,
522
            Unixcmd  => new S'("gcc"),
523
            Unixsws  =>
524
            new Argument_List'(new String'("-shared") & Init_Object_Dirs),
525
            Switches => Shared_Switches'Access,
526
            Params   => new Parameter_Array'(1 => Unlimited_Files),
527
            Defext   => "   "),
528
 
529
         Stack =>
530
           (Cname    => new S'("STACK"),
531
            Usage    => new S'("GNAT STACK /qualifiers ci_files"),
532
            VMS_Only => False,
533
            Unixcmd  => new S'("gnatstack"),
534
            Unixsws  => null,
535
            Switches => Stack_Switches'Access,
536
            Params   => new Parameter_Array'(1 => Unlimited_Files),
537
            Defext   => "ci" & ASCII.NUL),
538
 
539
         Stub =>
540
           (Cname    => new S'("STUB"),
541
            Usage    => new S'("GNAT STUB file [directory]/qualifiers"),
542
            VMS_Only => False,
543
            Unixcmd  => new S'("gnatstub"),
544
            Unixsws  => null,
545
            Switches => Stub_Switches'Access,
546
            Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
547
            Defext   => "   "),
548
 
549
         Xref =>
550
           (Cname    => new S'("XREF"),
551
            Usage    => new S'("GNAT XREF filespec[,...] /qualifiers"),
552
            VMS_Only => False,
553
            Unixcmd  => new S'("gnatxref"),
554
            Unixsws  => null,
555
            Switches => Xref_Switches'Access,
556
            Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
557
            Defext   => "ali")
558
        );
559
   end Initialize;
560
 
561
   ------------------
562
   -- Invert_Sense --
563
   ------------------
564
 
565
   function Invert_Sense (S : String) return VMS_Data.String_Ptr is
566
      Sinv : String (1 .. S'Length * 2);
567
      --  Result (for sure long enough)
568
 
569
      Sinvp : Natural := 0;
570
      --  Pointer to output string
571
 
572
   begin
573
      for Sp in S'Range loop
574
         if Sp = S'First or else S (Sp - 1) = ',' then
575
            if S (Sp) = '!' then
576
               null;
577
            else
578
               Sinv (Sinvp + 1) := '!';
579
               Sinv (Sinvp + 2) := S (Sp);
580
               Sinvp := Sinvp + 2;
581
            end if;
582
 
583
         else
584
            Sinv (Sinvp + 1) := S (Sp);
585
            Sinvp := Sinvp + 1;
586
         end if;
587
      end loop;
588
 
589
      return new String'(Sinv (1 .. Sinvp));
590
   end Invert_Sense;
591
 
592
   ----------------------
593
   -- Is_Extensionless --
594
   ----------------------
595
 
596
   function Is_Extensionless (F : String) return Boolean is
597
   begin
598
      for J in reverse F'Range loop
599
         if F (J) = '.' then
600
            return False;
601
         elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
602
            return True;
603
         end if;
604
      end loop;
605
 
606
      return True;
607
   end Is_Extensionless;
608
 
609
   -----------
610
   -- Match --
611
   -----------
612
 
613
   function Match (S1, S2 : String) return Boolean is
614
      Dif : constant Integer := S2'First - S1'First;
615
 
616
   begin
617
 
618
      if S1'Length /= S2'Length then
619
         return False;
620
 
621
      else
622
         for J in S1'Range loop
623
            if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
624
               return False;
625
            end if;
626
         end loop;
627
 
628
         return True;
629
      end if;
630
   end Match;
631
 
632
   ------------------
633
   -- Match_Prefix --
634
   ------------------
635
 
636
   function Match_Prefix (S1, S2 : String) return Boolean is
637
   begin
638
      if S1'Length > S2'Length then
639
         return False;
640
      else
641
         return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
642
      end if;
643
   end Match_Prefix;
644
 
645
   -------------------
646
   -- Matching_Name --
647
   -------------------
648
 
649
   function Matching_Name
650
     (S     : String;
651
      Itm   : Item_Ptr;
652
      Quiet : Boolean := False) return Item_Ptr
653
   is
654
      P1, P2 : Item_Ptr;
655
 
656
      procedure Err;
657
      --  Little procedure to output command/qualifier/option as appropriate
658
      --  and bump error count.
659
 
660
      ---------
661
      -- Err --
662
      ---------
663
 
664
      procedure Err is
665
      begin
666
         if Quiet then
667
            return;
668
         end if;
669
 
670
         Errors := Errors + 1;
671
 
672
         if Itm /= null then
673
            case Itm.Id is
674
               when Id_Command =>
675
                  Put (Standard_Error, "command");
676
 
677
               when Id_Switch =>
678
                  if Hostparm.OpenVMS then
679
                     Put (Standard_Error, "qualifier");
680
                  else
681
                     Put (Standard_Error, "switch");
682
                  end if;
683
 
684
               when Id_Option =>
685
                  Put (Standard_Error, "option");
686
 
687
            end case;
688
         else
689
            Put (Standard_Error, "input");
690
 
691
         end if;
692
 
693
         Put (Standard_Error, ": ");
694
         Put (Standard_Error, S);
695
      end Err;
696
 
697
   --  Start of processing for Matching_Name
698
 
699
   begin
700
      --  If exact match, that's the one we want
701
 
702
      P1 := Itm;
703
      while P1 /= null loop
704
         if Match (S, P1.Name.all) then
705
            return P1;
706
         else
707
            P1 := P1.Next;
708
         end if;
709
      end loop;
710
 
711
      --  Now check for prefix matches
712
 
713
      P1 := Itm;
714
      while P1 /= null loop
715
         if P1.Name.all = "/<other>" then
716
            return P1;
717
 
718
         elsif not Match_Prefix (S, P1.Name.all) then
719
            P1 := P1.Next;
720
 
721
         else
722
            --  Here we have found one matching prefix, so see if there is
723
            --  another one (which is an ambiguity)
724
 
725
            P2 := P1.Next;
726
            while P2 /= null loop
727
               if Match_Prefix (S, P2.Name.all) then
728
                  if not Quiet then
729
                     Put (Standard_Error, "ambiguous ");
730
                     Err;
731
                     Put (Standard_Error, " (matches ");
732
                     Put (Standard_Error, P1.Name.all);
733
 
734
                     while P2 /= null loop
735
                        if Match_Prefix (S, P2.Name.all) then
736
                           Put (Standard_Error, ',');
737
                           Put (Standard_Error, P2.Name.all);
738
                        end if;
739
 
740
                        P2 := P2.Next;
741
                     end loop;
742
 
743
                     Put_Line (Standard_Error, ")");
744
                  end if;
745
 
746
                  return null;
747
               end if;
748
 
749
               P2 := P2.Next;
750
            end loop;
751
 
752
            --  If we fall through that loop, then there was only one match
753
 
754
            return P1;
755
         end if;
756
      end loop;
757
 
758
      --  If we fall through outer loop, there was no match
759
 
760
      if not Quiet then
761
         Put (Standard_Error, "unrecognized ");
762
         Err;
763
         New_Line (Standard_Error);
764
      end if;
765
 
766
      return null;
767
   end Matching_Name;
768
 
769
   -----------------------
770
   -- OK_Alphanumerplus --
771
   -----------------------
772
 
773
   function OK_Alphanumerplus (S : String) return Boolean is
774
   begin
775
      if S'Length = 0 then
776
         return False;
777
 
778
      else
779
         for J in S'Range loop
780
            if not (Is_Alphanumeric (S (J)) or else
781
                    S (J) = '_' or else S (J) = '$')
782
            then
783
               return False;
784
            end if;
785
         end loop;
786
 
787
         return True;
788
      end if;
789
   end OK_Alphanumerplus;
790
 
791
   ----------------
792
   -- OK_Integer --
793
   ----------------
794
 
795
   function OK_Integer (S : String) return Boolean is
796
   begin
797
      if S'Length = 0 then
798
         return False;
799
 
800
      else
801
         for J in S'Range loop
802
            if not Is_Digit (S (J)) then
803
               return False;
804
            end if;
805
         end loop;
806
 
807
         return True;
808
      end if;
809
   end OK_Integer;
810
 
811
   --------------------
812
   -- Output_Version --
813
   --------------------
814
 
815
   procedure Output_Version is
816
   begin
817
      if AAMP_On_Target then
818
         Put ("GNAAMP ");
819
      else
820
         Put ("GNAT ");
821
      end if;
822
 
823
      Put_Line (Gnatvsn.Gnat_Version_String);
824
      Put_Line ("Copyright 1996-" &
825
                Current_Year &
826
                ", Free Software Foundation, Inc.");
827
   end Output_Version;
828
 
829
   -----------
830
   -- Place --
831
   -----------
832
 
833
   procedure Place (C : Character) is
834
   begin
835
      if Cargs then
836
         Cargs_Buffer.Append (C);
837
      else
838
         Buffer.Append (C);
839
      end if;
840
   end Place;
841
 
842
   procedure Place (S : String) is
843
   begin
844
      for J in S'Range loop
845
         Place (S (J));
846
      end loop;
847
   end Place;
848
 
849
   -----------------
850
   -- Place_Lower --
851
   -----------------
852
 
853
   procedure Place_Lower (S : String) is
854
   begin
855
      for J in S'Range loop
856
         Place (To_Lower (S (J)));
857
      end loop;
858
   end Place_Lower;
859
 
860
   -------------------------
861
   -- Place_Unix_Switches --
862
   -------------------------
863
 
864
   procedure Place_Unix_Switches (S : VMS_Data.String_Ptr) is
865
      P1, P2, P3 : Natural;
866
      Remove     : Boolean;
867
      Slen, Sln2 : Natural;
868
      Wild_Card  : Boolean := False;
869
 
870
   begin
871
      P1 := S'First;
872
      while P1 <= S'Last loop
873
         if S (P1) = '!' then
874
            P1 := P1 + 1;
875
            Remove := True;
876
         else
877
            Remove := False;
878
         end if;
879
 
880
         P2 := P1;
881
         pragma Assert (S (P1) = '-' or else S (P1) = '`');
882
 
883
         while P2 < S'Last and then S (P2 + 1) /= ',' loop
884
            P2 := P2 + 1;
885
         end loop;
886
 
887
         --  Switch is now in S (P1 .. P2)
888
 
889
         Slen := P2 - P1 + 1;
890
 
891
         if Remove then
892
            Wild_Card := S (P2) = '*';
893
 
894
            if Wild_Card then
895
               Slen := Slen - 1;
896
               P2   := P2 - 1;
897
            end if;
898
 
899
            P3 := 1;
900
            while P3 <= Buffer.Last - Slen loop
901
               if Buffer.Table (P3) = ' '
902
                 and then String (Buffer.Table (P3 + 1 .. P3 + Slen)) =
903
                                                             S (P1 .. P2)
904
                 and then (Wild_Card
905
                             or else
906
                           P3 + Slen = Buffer.Last
907
                             or else
908
                           Buffer.Table (P3 + Slen + 1) = ' ')
909
               then
910
                  Sln2 := Slen;
911
 
912
                  if Wild_Card then
913
                     while P3 + Sln2 /= Buffer.Last
914
                       and then Buffer.Table (P3 + Sln2 + 1) /= ' '
915
                     loop
916
                        Sln2 := Sln2 + 1;
917
                     end loop;
918
                  end if;
919
 
920
                  Buffer.Table (P3 .. Buffer.Last - Sln2 - 1) :=
921
                    Buffer.Table (P3 + Sln2 + 1 .. Buffer.Last);
922
                  Buffer.Set_Last (Buffer.Last - Sln2 - 1);
923
 
924
               else
925
                  P3 := P3 + 1;
926
               end if;
927
            end loop;
928
 
929
            if Wild_Card then
930
               P2 := P2 + 1;
931
            end if;
932
 
933
         else
934
            pragma Assert (S (P2) /= '*');
935
            Place (' ');
936
 
937
            if S (P1) = '`' then
938
               P1 := P1 + 1;
939
            end if;
940
 
941
            Place (S (P1 .. P2));
942
         end if;
943
 
944
         P1 := P2 + 2;
945
      end loop;
946
   end Place_Unix_Switches;
947
 
948
   -----------------------------
949
   -- Preprocess_Command_Data --
950
   -----------------------------
951
 
952
   procedure Preprocess_Command_Data is
953
   begin
954
      for C in Real_Command_Type loop
955
         declare
956
            Command : constant Item_Ptr := new Command_Item;
957
 
958
            Last_Switch : Item_Ptr;
959
            --  Last switch in list
960
 
961
         begin
962
            --  Link new command item into list of commands
963
 
964
            if Last_Command = null then
965
               Commands := Command;
966
            else
967
               Last_Command.Next := Command;
968
            end if;
969
 
970
            Last_Command := Command;
971
 
972
            --  Fill in fields of new command item
973
 
974
            Command.Name    := Command_List (C).Cname;
975
            Command.Usage   := Command_List (C).Usage;
976
            Command.Command := C;
977
 
978
            if Command_List (C).Unixsws = null then
979
               Command.Unix_String := Command_List (C).Unixcmd;
980
            else
981
               declare
982
                  Cmd  : String (1 .. 5_000);
983
                  Last : Natural := 0;
984
                  Sws  : constant Argument_List_Access :=
985
                           Command_List (C).Unixsws;
986
 
987
               begin
988
                  Cmd (1 .. Command_List (C).Unixcmd'Length) :=
989
                    Command_List (C).Unixcmd.all;
990
                  Last := Command_List (C).Unixcmd'Length;
991
 
992
                  for J in Sws'Range loop
993
                     Last := Last + 1;
994
                     Cmd (Last) := ' ';
995
                     Cmd (Last + 1 .. Last + Sws (J)'Length) :=
996
                       Sws (J).all;
997
                     Last := Last + Sws (J)'Length;
998
                  end loop;
999
 
1000
                  Command.Unix_String := new String'(Cmd (1 .. Last));
1001
               end;
1002
            end if;
1003
 
1004
            Command.Params := Command_List (C).Params;
1005
            Command.Defext := Command_List (C).Defext;
1006
 
1007
            Validate_Command_Or_Option (Command.Name);
1008
 
1009
            --  Process the switch list
1010
 
1011
            for S in Command_List (C).Switches'Range loop
1012
               declare
1013
                  SS : constant VMS_Data.String_Ptr :=
1014
                         Command_List (C).Switches (S);
1015
                  P  : Natural := SS'First;
1016
                  Sw : Item_Ptr := new Switch_Item;
1017
 
1018
                  Last_Opt : Item_Ptr;
1019
                  --  Pointer to last option
1020
 
1021
               begin
1022
                  --  Link new switch item into list of switches
1023
 
1024
                  if Last_Switch = null then
1025
                     Command.Switches := Sw;
1026
                  else
1027
                     Last_Switch.Next := Sw;
1028
                  end if;
1029
 
1030
                  Last_Switch := Sw;
1031
 
1032
                  --  Process switch string, first get name
1033
 
1034
                  while SS (P) /= ' ' and then SS (P) /= '=' loop
1035
                     P := P + 1;
1036
                  end loop;
1037
 
1038
                  Sw.Name := new String'(SS (SS'First .. P - 1));
1039
 
1040
                  --  Direct translation case
1041
 
1042
                  if SS (P) = ' ' then
1043
                     Sw.Translation := T_Direct;
1044
                     Sw.Unix_String := new String'(SS (P + 1 .. SS'Last));
1045
                     Validate_Unix_Switch (Sw.Unix_String);
1046
 
1047
                     if SS (P - 1) = '>' then
1048
                        Sw.Translation := T_Other;
1049
 
1050
                     elsif SS (P + 1) = '`' then
1051
                        null;
1052
 
1053
                        --  Create the inverted case (/NO ..)
1054
 
1055
                     elsif SS (SS'First + 1 .. SS'First + 2) /= "NO" then
1056
                        Sw := new Switch_Item;
1057
                        Last_Switch.Next := Sw;
1058
                        Last_Switch := Sw;
1059
 
1060
                        Sw.Name :=
1061
                          new String'("/NO" & SS (SS'First + 1 .. P - 1));
1062
                        Sw.Translation := T_Direct;
1063
                        Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
1064
                        Validate_Unix_Switch (Sw.Unix_String);
1065
                     end if;
1066
 
1067
                  --  Directories translation case
1068
 
1069
                  elsif SS (P + 1) = '*' then
1070
                     pragma Assert (SS (SS'Last) = '*');
1071
                     Sw.Translation := T_Directories;
1072
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1073
                     Validate_Unix_Switch (Sw.Unix_String);
1074
 
1075
                  --  Directory translation case
1076
 
1077
                  elsif SS (P + 1) = '%' then
1078
                     pragma Assert (SS (SS'Last) = '%');
1079
                     Sw.Translation := T_Directory;
1080
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1081
                     Validate_Unix_Switch (Sw.Unix_String);
1082
 
1083
                  --  File translation case
1084
 
1085
                  elsif SS (P + 1) = '@' then
1086
                     pragma Assert (SS (SS'Last) = '@');
1087
                     Sw.Translation := T_File;
1088
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1089
                     Validate_Unix_Switch (Sw.Unix_String);
1090
 
1091
                  --  No space file translation case
1092
 
1093
                  elsif SS (P + 1) = '<' then
1094
                     pragma Assert (SS (SS'Last) = '>');
1095
                     Sw.Translation := T_No_Space_File;
1096
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1097
                     Validate_Unix_Switch (Sw.Unix_String);
1098
 
1099
                  --  Numeric translation case
1100
 
1101
                  elsif SS (P + 1) = '#' then
1102
                     pragma Assert (SS (SS'Last) = '#');
1103
                     Sw.Translation := T_Numeric;
1104
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1105
                     Validate_Unix_Switch (Sw.Unix_String);
1106
 
1107
                  --  Alphanumerplus translation case
1108
 
1109
                  elsif SS (P + 1) = '|' then
1110
                     pragma Assert (SS (SS'Last) = '|');
1111
                     Sw.Translation := T_Alphanumplus;
1112
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1113
                     Validate_Unix_Switch (Sw.Unix_String);
1114
 
1115
                  --  String translation case
1116
 
1117
                  elsif SS (P + 1) = '"' then
1118
                     pragma Assert (SS (SS'Last) = '"');
1119
                     Sw.Translation := T_String;
1120
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
1121
                     Validate_Unix_Switch (Sw.Unix_String);
1122
 
1123
                  --  Commands translation case
1124
 
1125
                  elsif SS (P + 1) = '?' then
1126
                     Sw.Translation := T_Commands;
1127
                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last));
1128
 
1129
                  --  Options translation case
1130
 
1131
                  else
1132
                     Sw.Translation := T_Options;
1133
                     Sw.Unix_String := new String'("");
1134
 
1135
                     P := P + 1; -- bump past =
1136
                     while P <= SS'Last loop
1137
                        declare
1138
                           Opt : constant Item_Ptr := new Option_Item;
1139
                           Q   : Natural;
1140
 
1141
                        begin
1142
                           --  Link new option item into options list
1143
 
1144
                           if Last_Opt = null then
1145
                              Sw.Options := Opt;
1146
                           else
1147
                              Last_Opt.Next := Opt;
1148
                           end if;
1149
 
1150
                           Last_Opt := Opt;
1151
 
1152
                           --  Fill in fields of new option item
1153
 
1154
                           Q := P;
1155
                           while SS (Q) /= ' ' loop
1156
                              Q := Q + 1;
1157
                           end loop;
1158
 
1159
                           Opt.Name := new String'(SS (P .. Q - 1));
1160
                           Validate_Command_Or_Option (Opt.Name);
1161
 
1162
                           P := Q + 1;
1163
                           Q := P;
1164
 
1165
                           while Q <= SS'Last and then SS (Q) /= ' ' loop
1166
                              Q := Q + 1;
1167
                           end loop;
1168
 
1169
                           Opt.Unix_String := new String'(SS (P .. Q - 1));
1170
                           Validate_Unix_Switch (Opt.Unix_String);
1171
                           P := Q + 1;
1172
                        end;
1173
                     end loop;
1174
                  end if;
1175
               end;
1176
            end loop;
1177
         end;
1178
      end loop;
1179
   end Preprocess_Command_Data;
1180
 
1181
   ----------------------
1182
   -- Process_Argument --
1183
   ----------------------
1184
 
1185
   procedure Process_Argument (The_Command : in out Command_Type) is
1186
      Argv    : String_Access;
1187
      Arg_Idx : Integer;
1188
 
1189
      function Get_Arg_End
1190
        (Argv    : String;
1191
         Arg_Idx : Integer) return Integer;
1192
      --  Begins looking at Arg_Idx + 1 and returns the index of the
1193
      --  last character before a slash or else the index of the last
1194
      --  character in the string Argv.
1195
 
1196
      -----------------
1197
      -- Get_Arg_End --
1198
      -----------------
1199
 
1200
      function Get_Arg_End
1201
        (Argv    : String;
1202
         Arg_Idx : Integer) return Integer
1203
      is
1204
      begin
1205
         for J in Arg_Idx + 1 .. Argv'Last loop
1206
            if Argv (J) = '/' then
1207
               return J - 1;
1208
            end if;
1209
         end loop;
1210
 
1211
         return Argv'Last;
1212
      end Get_Arg_End;
1213
 
1214
      --  Start of processing for Process_Argument
1215
 
1216
   begin
1217
      Cargs := False;
1218
 
1219
      --  If an argument file is open, read the next non empty line
1220
 
1221
      if Is_Open (Arg_File) then
1222
         declare
1223
            Line : String (1 .. 256);
1224
            Last : Natural;
1225
         begin
1226
            loop
1227
               Get_Line (Arg_File, Line, Last);
1228
               exit when Last /= 0 or else End_Of_File (Arg_File);
1229
            end loop;
1230
 
1231
            --  If the end of the argument file has been reached, close it
1232
 
1233
            if End_Of_File (Arg_File) then
1234
               Close (Arg_File);
1235
 
1236
               --  If the last line was empty, return after increasing Arg_Num
1237
               --  to go to the next argument on the comment line.
1238
 
1239
               if Last = 0 then
1240
                  Arg_Num := Arg_Num + 1;
1241
                  return;
1242
               end if;
1243
            end if;
1244
 
1245
            Argv := new String'(Line (1 .. Last));
1246
            Arg_Idx := 1;
1247
 
1248
            if Argv (1) = '@' then
1249
               Put_Line (Standard_Error, "argument file cannot contain @cmd");
1250
               raise Error_Exit;
1251
            end if;
1252
         end;
1253
 
1254
      else
1255
         --  No argument file is open, get the argument on the command line
1256
 
1257
         Argv := new String'(Argument (Arg_Num));
1258
         Arg_Idx := Argv'First;
1259
 
1260
         --  Check if this is the specification of an argument file
1261
 
1262
         if Argv (Arg_Idx) = '@' then
1263
            --  The first argument on the command line cannot be an argument
1264
            --  file.
1265
 
1266
            if Arg_Num = 1 then
1267
               Put_Line
1268
                 (Standard_Error,
1269
                  "Cannot specify argument line before command");
1270
               raise Error_Exit;
1271
            end if;
1272
 
1273
            --  Open the file, after conversion of the name to canonical form.
1274
            --  Fail if file is not found.
1275
 
1276
            declare
1277
               Canonical_File_Name : String_Access :=
1278
                 To_Canonical_File_Spec (Argv (Arg_Idx + 1 .. Argv'Last));
1279
            begin
1280
               Open (Arg_File, In_File, Canonical_File_Name.all);
1281
               Free (Canonical_File_Name);
1282
               return;
1283
 
1284
            exception
1285
               when others =>
1286
                  Put (Standard_Error, "Cannot open argument file """);
1287
                  Put (Standard_Error, Argv (Arg_Idx + 1 .. Argv'Last));
1288
                  Put_Line (Standard_Error, """");
1289
                  raise Error_Exit;
1290
            end;
1291
         end if;
1292
      end if;
1293
 
1294
      <<Tryagain_After_Coalesce>>
1295
      loop
1296
         declare
1297
            Next_Arg_Idx : Integer;
1298
            Arg          : String_Access;
1299
 
1300
         begin
1301
            Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
1302
            Arg := new String'(Argv (Arg_Idx .. Next_Arg_Idx));
1303
 
1304
            --  The first one must be a command name
1305
 
1306
            if Arg_Num = 1 and then Arg_Idx = Argv'First then
1307
               Command := Matching_Name (Arg.all, Commands);
1308
 
1309
               if Command = null then
1310
                  raise Error_Exit;
1311
               end if;
1312
 
1313
               The_Command := Command.Command;
1314
               Output_File_Expected := False;
1315
 
1316
               --  Give usage information if only command given
1317
 
1318
               if Argument_Count = 1
1319
                 and then Next_Arg_Idx = Argv'Last
1320
               then
1321
                  Output_Version;
1322
                  New_Line;
1323
                  Put_Line
1324
                    ("List of available qualifiers and options");
1325
                  New_Line;
1326
 
1327
                  Put (Command.Usage.all);
1328
                  Set_Col (53);
1329
                  Put_Line (Command.Unix_String.all);
1330
 
1331
                  declare
1332
                     Sw : Item_Ptr := Command.Switches;
1333
 
1334
                  begin
1335
                     while Sw /= null loop
1336
                        Put ("   ");
1337
                        Put (Sw.Name.all);
1338
 
1339
                        case Sw.Translation is
1340
 
1341
                           when T_Other =>
1342
                              Set_Col (53);
1343
                              Put_Line (Sw.Unix_String.all &
1344
                                        "/<other>");
1345
 
1346
                           when T_Direct =>
1347
                              Set_Col (53);
1348
                              Put_Line (Sw.Unix_String.all);
1349
 
1350
                           when T_Directories =>
1351
                              Put ("=(direc,direc,..direc)");
1352
                              Set_Col (53);
1353
                              Put (Sw.Unix_String.all);
1354
                              Put (" direc ");
1355
                              Put (Sw.Unix_String.all);
1356
                              Put_Line (" direc ...");
1357
 
1358
                           when T_Directory =>
1359
                              Put ("=directory");
1360
                              Set_Col (53);
1361
                              Put (Sw.Unix_String.all);
1362
 
1363
                              if Sw.Unix_String (Sw.Unix_String'Last)
1364
                              /= '='
1365
                              then
1366
                                 Put (' ');
1367
                              end if;
1368
 
1369
                              Put_Line ("directory ");
1370
 
1371
                           when T_File | T_No_Space_File =>
1372
                              Put ("=file");
1373
                              Set_Col (53);
1374
                              Put (Sw.Unix_String.all);
1375
 
1376
                              if Sw.Translation = T_File
1377
                                and then Sw.Unix_String
1378
                                  (Sw.Unix_String'Last) /= '='
1379
                              then
1380
                                 Put (' ');
1381
                              end if;
1382
 
1383
                              Put_Line ("file ");
1384
 
1385
                           when T_Numeric =>
1386
                              Put ("=nnn");
1387
                              Set_Col (53);
1388
 
1389
                              if Sw.Unix_String
1390
                                (Sw.Unix_String'First) = '`'
1391
                              then
1392
                                 Put (Sw.Unix_String
1393
                                        (Sw.Unix_String'First + 1
1394
                                         .. Sw.Unix_String'Last));
1395
                              else
1396
                                 Put (Sw.Unix_String.all);
1397
                              end if;
1398
 
1399
                              Put_Line ("nnn");
1400
 
1401
                           when T_Alphanumplus =>
1402
                              Put ("=xyz");
1403
                              Set_Col (53);
1404
 
1405
                              if Sw.Unix_String
1406
                                (Sw.Unix_String'First) = '`'
1407
                              then
1408
                                 Put (Sw.Unix_String
1409
                                        (Sw.Unix_String'First + 1
1410
                                         .. Sw.Unix_String'Last));
1411
                              else
1412
                                 Put (Sw.Unix_String.all);
1413
                              end if;
1414
 
1415
                              Put_Line ("xyz");
1416
 
1417
                           when T_String =>
1418
                              Put ("=");
1419
                              Put ('"');
1420
                              Put ("<string>");
1421
                              Put ('"');
1422
                              Set_Col (53);
1423
 
1424
                              Put (Sw.Unix_String.all);
1425
 
1426
                              if Sw.Unix_String
1427
                                (Sw.Unix_String'Last) /= '='
1428
                              then
1429
                                 Put (' ');
1430
                              end if;
1431
 
1432
                              Put ("<string>");
1433
                              New_Line;
1434
 
1435
                           when T_Commands =>
1436
                              Put (" (switches for ");
1437
                              Put (Sw.Unix_String
1438
                                     (Sw.Unix_String'First + 7
1439
                                      .. Sw.Unix_String'Last));
1440
                              Put (')');
1441
                              Set_Col (53);
1442
                              Put (Sw.Unix_String
1443
                                     (Sw.Unix_String'First
1444
                                      .. Sw.Unix_String'First + 5));
1445
                              Put_Line (" switches");
1446
 
1447
                           when T_Options =>
1448
                              declare
1449
                                 Opt : Item_Ptr := Sw.Options;
1450
 
1451
                              begin
1452
                                 Put_Line ("=(option,option..)");
1453
 
1454
                                 while Opt /= null loop
1455
                                    Put ("      ");
1456
                                    Put (Opt.Name.all);
1457
 
1458
                                    if Opt = Sw.Options then
1459
                                       Put (" (D)");
1460
                                    end if;
1461
 
1462
                                    Set_Col (53);
1463
                                    Put_Line (Opt.Unix_String.all);
1464
                                    Opt := Opt.Next;
1465
                                 end loop;
1466
                              end;
1467
 
1468
                        end case;
1469
 
1470
                        Sw := Sw.Next;
1471
                     end loop;
1472
                  end;
1473
 
1474
                  raise Normal_Exit;
1475
               end if;
1476
 
1477
            --  Special handling for internal debugging switch /?
1478
 
1479
            elsif Arg.all = "/?" then
1480
               Display_Command := True;
1481
               Output_File_Expected := False;
1482
 
1483
            --  Special handling of internal option /KEEP_TEMPORARY_FILES
1484
 
1485
            elsif Arg'Length >= 7
1486
              and then Matching_Name
1487
                         (Arg.all, Keep_Temps_Option, True) /= null
1488
            then
1489
               Opt.Keep_Temporary_Files := True;
1490
 
1491
            --  Copy -switch unchanged, as well as +rule
1492
 
1493
            elsif Arg (Arg'First) = '-' or else Arg (Arg'First) = '+' then
1494
               Place (' ');
1495
               Place (Arg.all);
1496
 
1497
               --  Set Output_File_Expected for the next argument
1498
 
1499
               Output_File_Expected :=
1500
                 Arg.all = "-o" and then The_Command = Link;
1501
 
1502
               --  Copy quoted switch with quotes stripped
1503
 
1504
            elsif Arg (Arg'First) = '"' then
1505
               if Arg (Arg'Last) /= '"' then
1506
                  Put (Standard_Error, "misquoted argument: ");
1507
                  Put_Line (Standard_Error, Arg.all);
1508
                  Errors := Errors + 1;
1509
 
1510
               else
1511
                  Place (' ');
1512
                  Place (Arg (Arg'First + 1 .. Arg'Last - 1));
1513
               end if;
1514
 
1515
               Output_File_Expected := False;
1516
 
1517
               --  Parameter Argument
1518
 
1519
            elsif Arg (Arg'First) /= '/'
1520
              and then Make_Commands_Active = null
1521
            then
1522
               Param_Count := Param_Count + 1;
1523
 
1524
               if Param_Count <= Command.Params'Length then
1525
 
1526
                  case Command.Params (Param_Count) is
1527
 
1528
                     when File | Optional_File =>
1529
                        declare
1530
                           Normal_File : constant String_Access :=
1531
                             To_Canonical_File_Spec
1532
                               (Arg.all);
1533
 
1534
                        begin
1535
                           Place (' ');
1536
                           Place_Lower (Normal_File.all);
1537
 
1538
                           if Is_Extensionless (Normal_File.all)
1539
                             and then Command.Defext /= "   "
1540
                           then
1541
                              Place ('.');
1542
                              Place (Command.Defext);
1543
                           end if;
1544
                        end;
1545
 
1546
                     when Unlimited_Files =>
1547
                        declare
1548
                           Normal_File : constant String_Access :=
1549
                             To_Canonical_File_Spec
1550
                               (Arg.all);
1551
 
1552
                           File_Is_Wild : Boolean := False;
1553
                           File_List    : String_Access_List_Access;
1554
 
1555
                        begin
1556
                           for J in Arg'Range loop
1557
                              if Arg (J) = '*'
1558
                                or else Arg (J) = '%'
1559
                              then
1560
                                 File_Is_Wild := True;
1561
                              end if;
1562
                           end loop;
1563
 
1564
                           if File_Is_Wild then
1565
                              File_List := To_Canonical_File_List
1566
                                (Arg.all, False);
1567
 
1568
                              for J in File_List.all'Range loop
1569
                                 Place (' ');
1570
                                 Place_Lower (File_List.all (J).all);
1571
                              end loop;
1572
 
1573
                           else
1574
                              Place (' ');
1575
                              Place_Lower (Normal_File.all);
1576
 
1577
                              --  Add extension if not present, except after
1578
                              --  switch -o.
1579
 
1580
                              if Is_Extensionless (Normal_File.all)
1581
                                and then Command.Defext /= "   "
1582
                                and then not Output_File_Expected
1583
                              then
1584
                                 Place ('.');
1585
                                 Place (Command.Defext);
1586
                              end if;
1587
                           end if;
1588
 
1589
                           Param_Count := Param_Count - 1;
1590
                        end;
1591
 
1592
                     when Other_As_Is =>
1593
                        Place (' ');
1594
                        Place (Arg.all);
1595
 
1596
                     when Unlimited_As_Is =>
1597
                        Place (' ');
1598
                        Place (Arg.all);
1599
                        Param_Count := Param_Count - 1;
1600
 
1601
                     when Files_Or_Wildcard =>
1602
 
1603
                        --  Remove spaces from a comma separated list
1604
                        --  of file names and adjust control variables
1605
                        --  accordingly.
1606
 
1607
                        while Arg_Num < Argument_Count and then
1608
                          (Argv (Argv'Last) = ',' xor
1609
                             Argument (Arg_Num + 1)
1610
                             (Argument (Arg_Num + 1)'First) = ',')
1611
                        loop
1612
                           Argv := new String'
1613
                             (Argv.all & Argument (Arg_Num + 1));
1614
                           Arg_Num := Arg_Num + 1;
1615
                           Arg_Idx := Argv'First;
1616
                           Next_Arg_Idx :=
1617
                             Get_Arg_End (Argv.all, Arg_Idx);
1618
                           Arg := new String'
1619
                             (Argv (Arg_Idx .. Next_Arg_Idx));
1620
                        end loop;
1621
 
1622
                        --  Parse the comma separated list of VMS
1623
                        --  filenames and place them on the command
1624
                        --  line as space separated Unix style
1625
                        --  filenames. Lower case and add default
1626
                        --  extension as appropriate.
1627
 
1628
                        declare
1629
                           Arg1_Idx : Integer := Arg'First;
1630
 
1631
                           function Get_Arg1_End
1632
                             (Arg     : String;
1633
                              Arg_Idx : Integer) return Integer;
1634
                           --  Begins looking at Arg_Idx + 1 and
1635
                           --  returns the index of the last character
1636
                           --  before a comma or else the index of the
1637
                           --  last character in the string Arg.
1638
 
1639
                           ------------------
1640
                           -- Get_Arg1_End --
1641
                           ------------------
1642
 
1643
                           function Get_Arg1_End
1644
                             (Arg     : String;
1645
                              Arg_Idx : Integer) return Integer
1646
                           is
1647
                           begin
1648
                              for J in Arg_Idx + 1 .. Arg'Last loop
1649
                                 if Arg (J) = ',' then
1650
                                    return J - 1;
1651
                                 end if;
1652
                              end loop;
1653
 
1654
                              return Arg'Last;
1655
                           end Get_Arg1_End;
1656
 
1657
                        begin
1658
                           loop
1659
                              declare
1660
                                 Next_Arg1_Idx :
1661
                                 constant Integer :=
1662
                                   Get_Arg1_End (Arg.all, Arg1_Idx);
1663
 
1664
                                 Arg1 :
1665
                                 constant String :=
1666
                                   Arg (Arg1_Idx .. Next_Arg1_Idx);
1667
 
1668
                                 Normal_File :
1669
                                 constant String_Access :=
1670
                                   To_Canonical_File_Spec (Arg1);
1671
 
1672
                              begin
1673
                                 Place (' ');
1674
                                 Place_Lower (Normal_File.all);
1675
 
1676
                                 if Is_Extensionless (Normal_File.all)
1677
                                   and then Command.Defext /= "   "
1678
                                 then
1679
                                    Place ('.');
1680
                                    Place (Command.Defext);
1681
                                 end if;
1682
 
1683
                                 Arg1_Idx := Next_Arg1_Idx + 1;
1684
                              end;
1685
 
1686
                              exit when Arg1_Idx > Arg'Last;
1687
 
1688
                              --  Don't allow two or more commas in
1689
                              --  a row
1690
 
1691
                              if Arg (Arg1_Idx) = ',' then
1692
                                 Arg1_Idx := Arg1_Idx + 1;
1693
                                 if Arg1_Idx > Arg'Last or else
1694
                                   Arg (Arg1_Idx) = ','
1695
                                 then
1696
                                    Put_Line
1697
                                      (Standard_Error,
1698
                                       "Malformed Parameter: " &
1699
                                       Arg.all);
1700
                                    Put (Standard_Error, "usage: ");
1701
                                    Put_Line (Standard_Error,
1702
                                              Command.Usage.all);
1703
                                    raise Error_Exit;
1704
                                 end if;
1705
                              end if;
1706
 
1707
                           end loop;
1708
                        end;
1709
                  end case;
1710
               end if;
1711
 
1712
               --  Reset Output_File_Expected, in case it was True
1713
 
1714
               Output_File_Expected := False;
1715
 
1716
               --  Qualifier argument
1717
 
1718
            else
1719
               Output_File_Expected := False;
1720
 
1721
               Cargs := Command.Name.all = "COMPILE";
1722
 
1723
               --  This code is too heavily nested, should be
1724
               --  separated out as separate subprogram ???
1725
 
1726
               declare
1727
                  Sw   : Item_Ptr;
1728
                  SwP  : Natural;
1729
                  P2   : Natural;
1730
                  Endp : Natural := 0; -- avoid warning!
1731
                  Opt  : Item_Ptr;
1732
 
1733
               begin
1734
                  SwP := Arg'First;
1735
                  while SwP < Arg'Last
1736
                    and then Arg (SwP + 1) /= '='
1737
                  loop
1738
                     SwP := SwP + 1;
1739
                  end loop;
1740
 
1741
                  --  At this point, the switch name is in
1742
                  --  Arg (Arg'First..SwP) and if that is not the
1743
                  --  whole switch, then there is an equal sign at
1744
                  --  Arg (SwP + 1) and the rest of Arg is what comes
1745
                  --  after the equal sign.
1746
 
1747
                  --  If make commands are active, see if we have
1748
                  --  another COMMANDS_TRANSLATION switch belonging
1749
                  --  to gnatmake.
1750
 
1751
                  if Make_Commands_Active /= null then
1752
                     Sw :=
1753
                       Matching_Name
1754
                         (Arg (Arg'First .. SwP),
1755
                          Command.Switches,
1756
                          Quiet => True);
1757
 
1758
                     if Sw /= null
1759
                       and then Sw.Translation = T_Commands
1760
                     then
1761
                        null;
1762
 
1763
                     else
1764
                        Sw :=
1765
                          Matching_Name
1766
                            (Arg (Arg'First .. SwP),
1767
                             Make_Commands_Active.Switches,
1768
                             Quiet => False);
1769
                     end if;
1770
 
1771
                     --  For case of GNAT MAKE or CHOP, if we cannot
1772
                     --  find the switch, then see if it is a
1773
                     --  recognized compiler switch instead, and if
1774
                     --  so process the compiler switch.
1775
 
1776
                  elsif Command.Name.all = "MAKE"
1777
                    or else Command.Name.all = "CHOP" then
1778
                     Sw :=
1779
                       Matching_Name
1780
                         (Arg (Arg'First .. SwP),
1781
                          Command.Switches,
1782
                          Quiet => True);
1783
 
1784
                     if Sw = null then
1785
                        Sw :=
1786
                          Matching_Name
1787
                            (Arg (Arg'First .. SwP),
1788
                             Matching_Name
1789
                               ("COMPILE", Commands).Switches,
1790
                             Quiet => False);
1791
                     end if;
1792
 
1793
                     --  For all other cases, just search the relevant
1794
                     --  command.
1795
 
1796
                  else
1797
                     Sw :=
1798
                       Matching_Name
1799
                         (Arg (Arg'First .. SwP),
1800
                          Command.Switches,
1801
                          Quiet => False);
1802
                  end if;
1803
 
1804
                  if Sw /= null then
1805
                     if Cargs
1806
                       and then Sw.Name /= null
1807
                       and then
1808
                         (Sw.Name.all = "/PROJECT_FILE"          or else
1809
                          Sw.Name.all = "/MESSAGES_PROJECT_FILE" or else
1810
                          Sw.Name.all = "/EXTERNAL_REFERENCE")
1811
                     then
1812
                        Cargs := False;
1813
                     end if;
1814
 
1815
                     case Sw.Translation is
1816
                        when T_Direct =>
1817
                           Place_Unix_Switches (Sw.Unix_String);
1818
                           if SwP < Arg'Last
1819
                             and then Arg (SwP + 1) = '='
1820
                           then
1821
                              Put (Standard_Error,
1822
                                   "qualifier options ignored: ");
1823
                              Put_Line (Standard_Error, Arg.all);
1824
                           end if;
1825
 
1826
                        when T_Directories =>
1827
                           if SwP + 1 > Arg'Last then
1828
                              Put (Standard_Error,
1829
                                   "missing directories for: ");
1830
                              Put_Line (Standard_Error, Arg.all);
1831
                              Errors := Errors + 1;
1832
 
1833
                           elsif Arg (SwP + 2) /= '(' then
1834
                              SwP := SwP + 2;
1835
                              Endp := Arg'Last;
1836
 
1837
                           elsif Arg (Arg'Last) /= ')' then
1838
 
1839
                              --  Remove spaces from a comma separated
1840
                              --  list of file names and adjust
1841
                              --  control variables accordingly.
1842
 
1843
                              if Arg_Num < Argument_Count and then
1844
                                (Argv (Argv'Last) = ',' xor
1845
                                   Argument (Arg_Num + 1)
1846
                                   (Argument (Arg_Num + 1)'First) = ',')
1847
                              then
1848
                                 Argv :=
1849
                                   new String'(Argv.all
1850
                                               & Argument
1851
                                                 (Arg_Num + 1));
1852
                                 Arg_Num := Arg_Num + 1;
1853
                                 Arg_Idx := Argv'First;
1854
                                 Next_Arg_Idx :=
1855
                                   Get_Arg_End (Argv.all, Arg_Idx);
1856
                                 Arg := new String'
1857
                                   (Argv (Arg_Idx .. Next_Arg_Idx));
1858
                                 goto Tryagain_After_Coalesce;
1859
                              end if;
1860
 
1861
                              Put (Standard_Error,
1862
                                   "incorrectly parenthesized " &
1863
                                   "or malformed argument: ");
1864
                              Put_Line (Standard_Error, Arg.all);
1865
                              Errors := Errors + 1;
1866
 
1867
                           else
1868
                              SwP := SwP + 3;
1869
                              Endp := Arg'Last - 1;
1870
                           end if;
1871
 
1872
                           while SwP <= Endp loop
1873
                              declare
1874
                                 Dir_Is_Wild       : Boolean := False;
1875
                                 Dir_Maybe_Is_Wild : Boolean := False;
1876
 
1877
                                 Dir_List : String_Access_List_Access;
1878
 
1879
                              begin
1880
                                 P2 := SwP;
1881
 
1882
                                 while P2 < Endp
1883
                                   and then Arg (P2 + 1) /= ','
1884
                                 loop
1885
                                    --  A wildcard directory spec on
1886
                                    --  VMS will contain either * or
1887
                                    --  % or ...
1888
 
1889
                                    if Arg (P2) = '*' then
1890
                                       Dir_Is_Wild := True;
1891
 
1892
                                    elsif Arg (P2) = '%' then
1893
                                       Dir_Is_Wild := True;
1894
 
1895
                                    elsif Dir_Maybe_Is_Wild
1896
                                      and then Arg (P2) = '.'
1897
                                      and then Arg (P2 + 1) = '.'
1898
                                    then
1899
                                       Dir_Is_Wild := True;
1900
                                       Dir_Maybe_Is_Wild := False;
1901
 
1902
                                    elsif Dir_Maybe_Is_Wild then
1903
                                       Dir_Maybe_Is_Wild := False;
1904
 
1905
                                    elsif Arg (P2) = '.'
1906
                                      and then Arg (P2 + 1) = '.'
1907
                                    then
1908
                                       Dir_Maybe_Is_Wild := True;
1909
 
1910
                                    end if;
1911
 
1912
                                    P2 := P2 + 1;
1913
                                 end loop;
1914
 
1915
                                 if Dir_Is_Wild then
1916
                                    Dir_List :=
1917
                                      To_Canonical_File_List
1918
                                        (Arg (SwP .. P2), True);
1919
 
1920
                                    for J in Dir_List.all'Range loop
1921
                                       Place_Unix_Switches
1922
                                         (Sw.Unix_String);
1923
                                       Place_Lower
1924
                                         (Dir_List.all (J).all);
1925
                                    end loop;
1926
 
1927
                                 else
1928
                                    Place_Unix_Switches
1929
                                      (Sw.Unix_String);
1930
                                    Place_Lower
1931
                                      (To_Canonical_Dir_Spec
1932
                                         (Arg (SwP .. P2), False).all);
1933
                                 end if;
1934
 
1935
                                 SwP := P2 + 2;
1936
                              end;
1937
                           end loop;
1938
 
1939
                        when T_Directory =>
1940
                           if SwP + 1 > Arg'Last then
1941
                              Put (Standard_Error,
1942
                                   "missing directory for: ");
1943
                              Put_Line (Standard_Error, Arg.all);
1944
                              Errors := Errors + 1;
1945
 
1946
                           else
1947
                              Place_Unix_Switches (Sw.Unix_String);
1948
 
1949
                              --  Some switches end in "=". No space
1950
                              --  here
1951
 
1952
                              if Sw.Unix_String
1953
                                (Sw.Unix_String'Last) /= '='
1954
                              then
1955
                                 Place (' ');
1956
                              end if;
1957
 
1958
                              Place_Lower
1959
                                (To_Canonical_Dir_Spec
1960
                                   (Arg (SwP + 2 .. Arg'Last),
1961
                                    False).all);
1962
                           end if;
1963
 
1964
                        when T_File | T_No_Space_File =>
1965
                           if SwP + 1 > Arg'Last then
1966
                              Put (Standard_Error,
1967
                                   "missing file for: ");
1968
                              Put_Line (Standard_Error, Arg.all);
1969
                              Errors := Errors + 1;
1970
 
1971
                           else
1972
                              Place_Unix_Switches (Sw.Unix_String);
1973
 
1974
                              --  Some switches end in "=". No space
1975
                              --  here.
1976
 
1977
                              if Sw.Translation = T_File
1978
                                and then Sw.Unix_String
1979
                                  (Sw.Unix_String'Last) /= '='
1980
                              then
1981
                                 Place (' ');
1982
                              end if;
1983
 
1984
                              Place_Lower
1985
                                (To_Canonical_File_Spec
1986
                                   (Arg (SwP + 2 .. Arg'Last)).all);
1987
                           end if;
1988
 
1989
                        when T_Numeric =>
1990
                           if OK_Integer (Arg (SwP + 2 .. Arg'Last)) then
1991
                              Place_Unix_Switches (Sw.Unix_String);
1992
                              Place (Arg (SwP + 2 .. Arg'Last));
1993
 
1994
                           else
1995
                              Put (Standard_Error, "argument for ");
1996
                              Put (Standard_Error, Sw.Name.all);
1997
                              Put_Line
1998
                                (Standard_Error, " must be numeric");
1999
                              Errors := Errors + 1;
2000
                           end if;
2001
 
2002
                        when T_Alphanumplus =>
2003
                           if OK_Alphanumerplus
2004
                             (Arg (SwP + 2 .. Arg'Last))
2005
                           then
2006
                              Place_Unix_Switches (Sw.Unix_String);
2007
                              Place (Arg (SwP + 2 .. Arg'Last));
2008
 
2009
                           else
2010
                              Put (Standard_Error, "argument for ");
2011
                              Put (Standard_Error, Sw.Name.all);
2012
                              Put_Line (Standard_Error,
2013
                                        " must be alphanumeric");
2014
                              Errors := Errors + 1;
2015
                           end if;
2016
 
2017
                        when T_String =>
2018
 
2019
                           --  A String value must be extended to the
2020
                           --  end of the Argv, otherwise strings like
2021
                           --  "foo/bar" get split at the slash.
2022
 
2023
                           --  The beginning and ending of the string
2024
                           --  are flagged with embedded nulls which
2025
                           --  are removed when building the Spawn
2026
                           --  call. Nulls are use because they won't
2027
                           --  show up in a /? output. Quotes aren't
2028
                           --  used because that would make it
2029
                           --  difficult to embed them.
2030
 
2031
                           Place_Unix_Switches (Sw.Unix_String);
2032
 
2033
                           if Next_Arg_Idx /= Argv'Last then
2034
                              Next_Arg_Idx := Argv'Last;
2035
                              Arg := new String'
2036
                                (Argv (Arg_Idx .. Next_Arg_Idx));
2037
 
2038
                              SwP := Arg'First;
2039
                              while SwP < Arg'Last and then
2040
                              Arg (SwP + 1) /= '=' loop
2041
                                 SwP := SwP + 1;
2042
                              end loop;
2043
                           end if;
2044
 
2045
                           Place (ASCII.NUL);
2046
                           Place (Arg (SwP + 2 .. Arg'Last));
2047
                           Place (ASCII.NUL);
2048
 
2049
                        when T_Commands =>
2050
 
2051
                           --  Output -largs/-bargs/-cargs
2052
 
2053
                           Place (' ');
2054
                           Place (Sw.Unix_String
2055
                                    (Sw.Unix_String'First ..
2056
                                       Sw.Unix_String'First + 5));
2057
 
2058
                           if Sw.Unix_String
2059
                             (Sw.Unix_String'First + 7 ..
2060
                                Sw.Unix_String'Last) = "MAKE"
2061
                           then
2062
                              Make_Commands_Active := null;
2063
 
2064
                           else
2065
                              --  Set source of new commands, also
2066
                              --  setting this non-null indicates that
2067
                              --  we are in the special commands mode
2068
                              --  for processing the -xargs case.
2069
 
2070
                              Make_Commands_Active :=
2071
                                Matching_Name
2072
                                  (Sw.Unix_String
2073
                                       (Sw.Unix_String'First + 7 ..
2074
                                            Sw.Unix_String'Last),
2075
                                   Commands);
2076
                           end if;
2077
 
2078
                        when T_Options =>
2079
                           if SwP + 1 > Arg'Last then
2080
                              Place_Unix_Switches
2081
                                (Sw.Options.Unix_String);
2082
                              SwP := Endp + 1;
2083
 
2084
                           elsif Arg (SwP + 2) /= '(' then
2085
                              SwP := SwP + 2;
2086
                              Endp := Arg'Last;
2087
 
2088
                           elsif Arg (Arg'Last) /= ')' then
2089
                              Put (Standard_Error,
2090
                                   "incorrectly parenthesized argument: ");
2091
                              Put_Line (Standard_Error, Arg.all);
2092
                              Errors := Errors + 1;
2093
                              SwP := Endp + 1;
2094
 
2095
                           else
2096
                              SwP := SwP + 3;
2097
                              Endp := Arg'Last - 1;
2098
                           end if;
2099
 
2100
                           while SwP <= Endp loop
2101
                              P2 := SwP;
2102
 
2103
                              while P2 < Endp
2104
                                and then Arg (P2 + 1) /= ','
2105
                              loop
2106
                                 P2 := P2 + 1;
2107
                              end loop;
2108
 
2109
                              --  Option name is in Arg (SwP .. P2)
2110
 
2111
                              Opt := Matching_Name (Arg (SwP .. P2),
2112
                                                    Sw.Options);
2113
 
2114
                              if Opt /= null then
2115
                                 Place_Unix_Switches
2116
                                   (Opt.Unix_String);
2117
                              end if;
2118
 
2119
                              SwP := P2 + 2;
2120
                           end loop;
2121
 
2122
                        when T_Other =>
2123
                           Place_Unix_Switches
2124
                             (new String'(Sw.Unix_String.all &
2125
                                          Arg.all));
2126
 
2127
                     end case;
2128
                  end if;
2129
               end;
2130
            end if;
2131
 
2132
            Arg_Idx := Next_Arg_Idx + 1;
2133
         end;
2134
 
2135
         exit when Arg_Idx > Argv'Last;
2136
 
2137
      end loop;
2138
 
2139
      if not Is_Open (Arg_File) then
2140
         Arg_Num := Arg_Num + 1;
2141
      end if;
2142
   end Process_Argument;
2143
 
2144
   --------------------
2145
   -- Process_Buffer --
2146
   --------------------
2147
 
2148
   procedure Process_Buffer (S : String) is
2149
      P1, P2     : Natural;
2150
      Inside_Nul : Boolean := False;
2151
      Arg        : String (1 .. 1024);
2152
      Arg_Ctr    : Natural;
2153
 
2154
   begin
2155
      P1 := 1;
2156
      while P1 <= S'Last and then S (P1) = ' ' loop
2157
         P1 := P1 + 1;
2158
      end loop;
2159
 
2160
      Arg_Ctr := 1;
2161
      Arg (Arg_Ctr) := S (P1);
2162
 
2163
      while P1 <= S'Last loop
2164
         if S (P1) = ASCII.NUL then
2165
            if Inside_Nul then
2166
               Inside_Nul := False;
2167
            else
2168
               Inside_Nul := True;
2169
            end if;
2170
         end if;
2171
 
2172
         if S (P1) = ' ' and then not Inside_Nul then
2173
            P1 := P1 + 1;
2174
            Arg_Ctr := Arg_Ctr + 1;
2175
            Arg (Arg_Ctr) := S (P1);
2176
 
2177
         else
2178
            Last_Switches.Increment_Last;
2179
            P2 := P1;
2180
 
2181
            while P2 < S'Last
2182
              and then (S (P2 + 1) /= ' ' or else
2183
                        Inside_Nul)
2184
            loop
2185
               P2 := P2 + 1;
2186
               Arg_Ctr := Arg_Ctr + 1;
2187
               Arg (Arg_Ctr) := S (P2);
2188
               if S (P2) = ASCII.NUL then
2189
                  Arg_Ctr := Arg_Ctr - 1;
2190
 
2191
                  if Inside_Nul then
2192
                     Inside_Nul := False;
2193
                  else
2194
                     Inside_Nul := True;
2195
                  end if;
2196
               end if;
2197
            end loop;
2198
 
2199
            Last_Switches.Table (Last_Switches.Last) :=
2200
              new String'(String (Arg (1 .. Arg_Ctr)));
2201
            P1 := P2 + 2;
2202
 
2203
            exit when P1 > S'Last;
2204
 
2205
            Arg_Ctr := 1;
2206
            Arg (Arg_Ctr) := S (P1);
2207
         end if;
2208
      end loop;
2209
   end Process_Buffer;
2210
 
2211
   --------------------------------
2212
   -- Validate_Command_Or_Option --
2213
   --------------------------------
2214
 
2215
   procedure Validate_Command_Or_Option (N : VMS_Data.String_Ptr) is
2216
   begin
2217
      pragma Assert (N'Length > 0);
2218
 
2219
      for J in N'Range loop
2220
         if N (J) = '_' then
2221
            pragma Assert (N (J - 1) /= '_');
2222
            null;
2223
         else
2224
            pragma Assert (Is_Upper (N (J)) or else Is_Digit (N (J)));
2225
            null;
2226
         end if;
2227
      end loop;
2228
   end Validate_Command_Or_Option;
2229
 
2230
   --------------------------
2231
   -- Validate_Unix_Switch --
2232
   --------------------------
2233
 
2234
   procedure Validate_Unix_Switch (S : VMS_Data.String_Ptr) is
2235
   begin
2236
      if S (S'First) = '`' then
2237
         return;
2238
      end if;
2239
 
2240
      pragma Assert (S (S'First) = '-' or else S (S'First) = '!');
2241
 
2242
      for J in S'First + 1 .. S'Last loop
2243
         pragma Assert (S (J) /= ' ');
2244
 
2245
         if S (J) = '!' then
2246
            pragma Assert (S (J - 1) = ',' and then S (J + 1) = '-');
2247
            null;
2248
         end if;
2249
      end loop;
2250
   end Validate_Unix_Switch;
2251
 
2252
   --------------------
2253
   -- VMS_Conversion --
2254
   --------------------
2255
 
2256
   procedure VMS_Conversion (The_Command : out Command_Type) is
2257
      Result     : Command_Type := Undefined;
2258
      Result_Set : Boolean      := False;
2259
 
2260
   begin
2261
      Buffer.Init;
2262
 
2263
      --  First we must preprocess the string form of the command and options
2264
      --  list into the internal form that we use.
2265
 
2266
      Preprocess_Command_Data;
2267
 
2268
      --  If no parameters, give complete list of commands
2269
 
2270
      if Argument_Count = 0 then
2271
         Output_Version;
2272
         New_Line;
2273
         Put_Line ("List of available commands");
2274
         New_Line;
2275
 
2276
         while Commands /= null loop
2277
            Put (Commands.Usage.all);
2278
            Set_Col (53);
2279
            Put_Line (Commands.Unix_String.all);
2280
            Commands := Commands.Next;
2281
         end loop;
2282
 
2283
         raise Normal_Exit;
2284
      end if;
2285
 
2286
      --  Loop through arguments
2287
 
2288
      Arg_Num := 1;
2289
      while Arg_Num <= Argument_Count loop
2290
         Process_Argument (Result);
2291
 
2292
         if not Result_Set then
2293
            The_Command := Result;
2294
            Result_Set := True;
2295
         end if;
2296
      end loop;
2297
 
2298
      --  Gross error checking that the number of parameters is correct.
2299
      --  Not applicable to Unlimited_Files parameters.
2300
 
2301
      if (Param_Count = Command.Params'Length - 1
2302
            and then Command.Params (Param_Count + 1) = Unlimited_Files)
2303
        or else Param_Count <= Command.Params'Length
2304
      then
2305
         null;
2306
 
2307
      else
2308
         Put_Line (Standard_Error,
2309
                   "Parameter count of "
2310
                   & Integer'Image (Param_Count)
2311
                   & " not equal to expected "
2312
                   & Integer'Image (Command.Params'Length));
2313
         Put (Standard_Error, "usage: ");
2314
         Put_Line (Standard_Error, Command.Usage.all);
2315
         Errors := Errors + 1;
2316
      end if;
2317
 
2318
      if Errors > 0 then
2319
         raise Error_Exit;
2320
      else
2321
         --  Prepare arguments for a call to spawn, filtering out
2322
         --  embedded nulls place there to delineate strings.
2323
 
2324
         Process_Buffer (String (Buffer.Table (1 .. Buffer.Last)));
2325
 
2326
         if Cargs_Buffer.Last > 1 then
2327
            Last_Switches.Append (new String'("-cargs"));
2328
            Process_Buffer
2329
              (String (Cargs_Buffer.Table (1 .. Cargs_Buffer.Last)));
2330
         end if;
2331
      end if;
2332
   end VMS_Conversion;
2333
 
2334
end VMS_Conv;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.