1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1996-2012, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Gnatvsn
; use Gnatvsn
;
29 with Osint
; use Osint
;
30 with Targparm
; use Targparm
;
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
;
36 package body VMS_Conv
is
38 -------------------------
39 -- Internal Structures --
40 -------------------------
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
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.
50 type Item_Id
is (Id_Command
, Id_Switch
, Id_Option
);
52 type Translation_Type
is
55 -- A qualifier with no options.
56 -- Example: GNAT MAKE /VERBOSE
59 -- A qualifier followed by a list of directories
60 -- Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
63 -- A qualifier followed by one directory
64 -- Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
67 -- A qualifier followed by a filename
68 -- Example: GNAT LINK /EXECUTABLE=FOO.EXE
71 -- A qualifier followed by a filename
72 -- Example: GNAT MAKE /PROJECT_FILE=PRJ.GPR
75 -- A qualifier followed by a numeric value.
76 -- Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
79 -- A qualifier followed by a quoted string. Only used by
80 -- /IDENTIFICATION qualifier.
81 -- Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
84 -- A qualifier followed by a list of options.
85 -- Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
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
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
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
104 type Item
(Id
: Item_Id
);
105 type Item_Ptr
is access all Item
;
107 type Item
(Id
: Item_Id
) is record
109 -- Name of the command, switch (with slash) or option
112 -- Pointer to next item on list, always has the same Id value
114 Command
: Command_Type
:= Undefined
;
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.
126 -- Pointer to list of switch items for the command, linked
127 -- through the Next fields with null terminating the list.
130 -- Usage information, used only for errors and the default
131 -- list of commands output.
133 Params
: Parameter_Ref
;
134 -- Array of parameters
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.
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.
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.
156 -- No special fields needed, since Name and Unix_String are
157 -- sufficient to completely described an option.
162 subtype Command_Item
is Item
(Id_Command
);
163 subtype Switch_Item
is Item
(Id_Switch
);
164 subtype Option_Item
is Item
(Id_Option
);
166 Keep_Temps_Option
: constant Item_Ptr
:=
170 new String'("/KEEP_TEMPORARY_FILES"),
172 Command
=> Undefined
,
173 Unix_String
=> null);
175 Param_Count
: Natural := 0;
176 -- Number of parameter arguments so far
181 Arg_File
: Ada
.Text_IO
.File_Type
;
182 -- A file where arguments are read from
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.
188 Last_Command
: Item_Ptr
;
189 -- Pointer to last item in Commands list
192 -- Pointer to command item for current command
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
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.
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
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
221 Cargs
: Boolean := False;
222 -- When True, commands should go to Cargs_Buffer instead of Buffer table
224 function Init_Object_Dirs
return Argument_List
;
225 -- Get the list of the object directories
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.
232 function Is_Extensionless
(F
: String) return Boolean;
233 -- Returns true if the filename has no extension
235 function Match
(S1
, S2
: String) return Boolean;
236 -- Determines whether S1 and S2 match (this is a case insensitive match)
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).
242 function Matching_Name
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).
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.
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.
266 procedure Place
(C
: Character);
267 -- Place a single character in the buffer, updating Ptr
269 procedure Place
(S
: String);
270 -- Place a string character in the buffer, updating Ptr
272 procedure Place_Lower
(S
: String);
273 -- Place string in buffer, forcing letters to lower case, updating Ptr
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.
280 procedure Preprocess_Command_Data
;
281 -- Preprocess the string form of the command and options list into the
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.
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.
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.
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.
300 ----------------------
301 -- Init_Object_Dirs --
302 ----------------------
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
;
311 Object_Dir_Name
:= new String'(Object_Dir_Default_Prefix);
312 Get_Next_Dir_In_Path_Init (Object_Dir_Name);
316 Dir : constant String_Access :=
317 Get_Next_Dir_In_Path (Object_Dir_Name);
319 exit when Dir = null;
320 Object_Dirs := Object_Dirs + 1;
321 Object_Dir (Object_Dirs) :=
323 To_Canonical_Dir_Spec
325 (Normalize_Directory_Name
(Dir
.all).all,
326 True).all, True).all);
330 Object_Dirs
:= Object_Dirs
+ 1;
331 Object_Dir
(Object_Dirs
) := new String'("-lgnat");
333 if OpenVMS_On_Target then
334 Object_Dirs := Object_Dirs + 1;
335 Object_Dir (Object_Dirs) := new String'("-ldecgnat");
338 return Object_Dir
(1 .. Object_Dirs
);
339 end Init_Object_Dirs
;
345 procedure Initialize
is
349 (Cname
=> new S
'("BIND"),
350 Usage => new S'("GNAT BIND file[.ali] /qualifiers"),
352 Unixcmd
=> new S
'("gnatbind"),
354 Switches => Bind_Switches'Access,
355 Params => new Parameter_Array'(1 => Unlimited_Files
),
359 (Cname
=> new S
'("CHOP"),
360 Usage => new S'("GNAT CHOP file [directory] /qualifiers"),
362 Unixcmd
=> new S
'("gnatchop"),
364 Switches => Chop_Switches'Access,
365 Params => new Parameter_Array'(1 => File
, 2 => Optional_File
),
369 (Cname
=> new S
'("CLEAN"),
370 Usage => new S'("GNAT CLEAN /qualifiers files"),
372 Unixcmd
=> new S
'("gnatclean"),
374 Switches => Clean_Switches'Access,
375 Params => new Parameter_Array'(1 => File
),
379 (Cname
=> new S
'("COMPILE"),
380 Usage => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
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
),
391 (Cname
=> new S
'("CHECK"),
392 Usage => new S'("GNAT CHECK name /qualifiers"),
394 Unixcmd
=> new S
'("gnatcheck"),
396 Switches => Check_Switches'Access,
397 Params => new Parameter_Array'(1 => Unlimited_Files
),
401 (Cname
=> new S
'("SYNC"),
402 Usage => new S'("GNAT SYNC name /qualifiers"),
404 Unixcmd
=> new S
'("gnatsync"),
406 Switches => Sync_Switches'Access,
407 Params => new Parameter_Array'(1 => Unlimited_Files
),
411 (Cname
=> new S
'("ELIM"),
412 Usage => new S'("GNAT ELIM name /qualifiers"),
414 Unixcmd
=> new S
'("gnatelim"),
416 Switches => Elim_Switches'Access,
417 Params => new Parameter_Array'(1 => Other_As_Is
),
421 (Cname
=> new S
'("FIND"),
422 Usage => new S'("GNAT FIND pattern[:sourcefile[:line"
423 & "[:column]]] filespec[,...] /qualifiers"),
425 Unixcmd
=> new S
'("gnatfind"),
427 Switches => Find_Switches'Access,
428 Params => new Parameter_Array'(1 => Other_As_Is
,
429 2 => Files_Or_Wildcard
),
433 (Cname
=> new S
'("KRUNCH"),
434 Usage => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
436 Unixcmd
=> new S
'("gnatkr"),
438 Switches => Krunch_Switches'Access,
439 Params => new Parameter_Array'(1 => File
),
443 (Cname
=> new S
'("LINK"),
444 Usage => new S'("GNAT LINK file[.ali]"
445 & " [extra obj_&_lib_&_exe_&_opt files]"
448 Unixcmd
=> new S
'("gnatlink"),
450 Switches => Link_Switches'Access,
451 Params => new Parameter_Array'(1 => Unlimited_Files
),
455 (Cname
=> new S
'("LIST"),
456 Usage => new S'("GNAT LIST /qualifiers object_or_ali_file"),
458 Unixcmd
=> new S
'("gnatls"),
460 Switches => List_Switches'Access,
461 Params => new Parameter_Array'(1 => Unlimited_Files
),
465 (Cname
=> new S
'("MAKE"),
466 Usage => new S'("GNAT MAKE file(s) /qualifiers (includes "
467 & "COMPILE /qualifiers)"),
469 Unixcmd
=> new S
'("gnatmake"),
471 Switches => Make_Switches'Access,
472 Params => new Parameter_Array'(1 => Unlimited_Files
),
476 (Cname
=> new S
'("METRIC"),
477 Usage => new S'("GNAT METRIC /qualifiers source_file"),
479 Unixcmd
=> new S
'("gnatmetric"),
481 Switches => Metric_Switches'Access,
482 Params => new Parameter_Array'(1 => Unlimited_Files
),
486 (Cname
=> new S
'("NAME"),
487 Usage => new S'("GNAT NAME /qualifiers naming-pattern "
488 & "[naming-patterns]"),
490 Unixcmd
=> new S
'("gnatname"),
492 Switches => Name_Switches'Access,
493 Params => new Parameter_Array'(1 => Unlimited_As_Is
),
497 (Cname
=> new S
'("PREPROCESS"),
499 new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
501 Unixcmd
=> new S
'("gnatprep"),
503 Switches => Prep_Switches'Access,
504 Params => new Parameter_Array'(1 .. 3 => File
),
508 (Cname
=> new S
'("PRETTY"),
509 Usage => new S'("GNAT PRETTY /qualifiers source_file"),
511 Unixcmd
=> new S
'("gnatpp"),
513 Switches => Pretty_Switches'Access,
514 Params => new Parameter_Array'(1 => Unlimited_Files
),
518 (Cname
=> new S
'("SHARED"),
519 Usage => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt"
520 & "files] /qualifiers"),
522 Unixcmd
=> new S
'("gcc"),
524 new Argument_List'(new String'("-shared") & Init_Object_Dirs),
525 Switches => Shared_Switches'Access,
526 Params => new Parameter_Array'(1 => Unlimited_Files
),
530 (Cname
=> new S
'("STACK"),
531 Usage => new S'("GNAT STACK /qualifiers ci_files"),
533 Unixcmd
=> new S
'("gnatstack"),
535 Switches => Stack_Switches'Access,
536 Params => new Parameter_Array'(1 => Unlimited_Files
),
537 Defext
=> "ci" & ASCII
.NUL
),
540 (Cname
=> new S
'("STUB"),
541 Usage => new S'("GNAT STUB file [directory]/qualifiers"),
543 Unixcmd
=> new S
'("gnatstub"),
545 Switches => Stub_Switches'Access,
546 Params => new Parameter_Array'(1 => File
, 2 => Optional_File
),
550 (Cname
=> new S
'("TEST"),
551 Usage => new S'("GNAT TEST file(s) /qualifiers"),
553 Unixcmd
=> new S
'("gnattest"),
555 Switches => Make_Switches'Access,
556 Params => new Parameter_Array'(1 => Unlimited_Files
),
560 (Cname
=> new S
'("XREF"),
561 Usage => new S'("GNAT XREF filespec[,...] /qualifiers"),
563 Unixcmd
=> new S
'("gnatxref"),
565 Switches => Xref_Switches'Access,
566 Params => new Parameter_Array'(1 => Files_Or_Wildcard
),
575 function Invert_Sense
(S
: String) return VMS_Data
.String_Ptr
is
576 Sinv
: String (1 .. S
'Length * 2);
577 -- Result (for sure long enough)
579 Sinvp
: Natural := 0;
580 -- Pointer to output string
583 for Sp
in S
'Range loop
584 if Sp
= S
'First or else S
(Sp
- 1) = ',' then
588 Sinv
(Sinvp
+ 1) := '!';
589 Sinv
(Sinvp
+ 2) := S
(Sp
);
594 Sinv
(Sinvp
+ 1) := S
(Sp
);
599 return new String'(Sinv (1 .. Sinvp));
602 ----------------------
603 -- Is_Extensionless --
604 ----------------------
606 function Is_Extensionless (F : String) return Boolean is
608 for J in reverse F'Range loop
611 elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
617 end Is_Extensionless;
623 function Match (S1, S2 : String) return Boolean is
624 Dif : constant Integer := S2'First - S1'First;
628 if S1'Length /= S2'Length then
632 for J in S1'Range loop
633 if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
646 function Match_Prefix (S1, S2 : String) return Boolean is
648 if S1'Length > S2'Length then
651 return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
659 function Matching_Name
662 Quiet : Boolean := False) return Item_Ptr
667 -- Little procedure to output command/qualifier/option as appropriate
668 -- and bump error count.
680 Errors := Errors + 1;
685 Put (Standard_Error, "command");
688 if Hostparm.OpenVMS then
689 Put (Standard_Error, "qualifier");
691 Put (Standard_Error, "switch");
695 Put (Standard_Error, "option");
699 Put (Standard_Error, "input");
703 Put (Standard_Error, ": ");
704 Put (Standard_Error, S);
707 -- Start of processing for Matching_Name
710 -- If exact match, that's the one we want
713 while P1 /= null loop
714 if Match (S, P1.Name.all) then
721 -- Now check for prefix matches
724 while P1 /= null loop
725 if P1.Name.all = "/<other>" then
728 elsif not Match_Prefix (S, P1.Name.all) then
732 -- Here we have found one matching prefix, so see if there is
733 -- another one (which is an ambiguity)
736 while P2 /= null loop
737 if Match_Prefix (S, P2.Name.all) then
739 Put (Standard_Error, "ambiguous ");
741 Put (Standard_Error, " (matches ");
742 Put (Standard_Error, P1.Name.all);
744 while P2 /= null loop
745 if Match_Prefix (S, P2.Name.all) then
746 Put (Standard_Error, ',');
747 Put (Standard_Error, P2.Name.all);
753 Put_Line (Standard_Error, ")");
762 -- If we fall through that loop, then there was only one match
768 -- If we fall through outer loop, there was no match
771 Put (Standard_Error, "unrecognized ");
773 New_Line (Standard_Error);
779 -----------------------
780 -- OK_Alphanumerplus --
781 -----------------------
783 function OK_Alphanumerplus (S : String) return Boolean is
789 for J in S'Range loop
790 if not (Is_Alphanumeric (S (J)) or else
791 S (J) = '_
' or else S (J) = '$
')
799 end OK_Alphanumerplus;
805 function OK_Integer (S : String) return Boolean is
811 for J in S'Range loop
812 if not Is_Digit (S (J)) then
825 procedure Output_Version is
827 if AAMP_On_Target then
833 Put_Line (Gnatvsn.Gnat_Version_String);
834 Put_Line ("Copyright 1996-" &
836 ", Free Software Foundation, Inc.");
843 procedure Place (C : Character) is
846 Cargs_Buffer.Append (C);
852 procedure Place (S : String) is
854 for J in S'Range loop
863 procedure Place_Lower (S : String) is
865 for J in S'Range loop
866 Place (To_Lower (S (J)));
870 -------------------------
871 -- Place_Unix_Switches --
872 -------------------------
874 procedure Place_Unix_Switches (S : VMS_Data.String_Ptr) is
875 P1, P2, P3 : Natural;
877 Slen, Sln2 : Natural;
878 Wild_Card : Boolean := False;
882 while P1 <= S'Last loop
891 pragma Assert (S (P1) = '-' or else S (P1) = '`
');
893 while P2 < S'Last and then S (P2 + 1) /= ',' loop
897 -- Switch is now in S (P1 .. P2)
902 Wild_Card := S (P2) = '*';
910 while P3 <= Buffer.Last - Slen loop
911 if Buffer.Table (P3) = ' '
912 and then String (Buffer.Table (P3 + 1 .. P3 + Slen)) =
916 P3 + Slen = Buffer.Last
918 Buffer.Table (P3 + Slen + 1) = ' ')
923 while P3 + Sln2 /= Buffer.Last
924 and then Buffer.Table (P3 + Sln2 + 1) /= ' '
930 Buffer.Table (P3 .. Buffer.Last - Sln2 - 1) :=
931 Buffer.Table (P3 + Sln2 + 1 .. Buffer.Last);
932 Buffer.Set_Last (Buffer.Last - Sln2 - 1);
944 pragma Assert (S (P2) /= '*');
951 Place (S (P1 .. P2));
956 end Place_Unix_Switches;
958 -----------------------------
959 -- Preprocess_Command_Data --
960 -----------------------------
962 procedure Preprocess_Command_Data is
964 for C in Real_Command_Type loop
966 Command : constant Item_Ptr := new Command_Item;
968 Last_Switch : Item_Ptr;
969 -- Last switch in list
972 -- Link new command item into list of commands
974 if Last_Command = null then
977 Last_Command.Next := Command;
980 Last_Command := Command;
982 -- Fill in fields of new command item
984 Command.Name := Command_List (C).Cname;
985 Command.Usage := Command_List (C).Usage;
986 Command.Command := C;
988 if Command_List (C).Unixsws = null then
989 Command.Unix_String := Command_List (C).Unixcmd;
992 Cmd : String (1 .. 5_000);
994 Sws : constant Argument_List_Access :=
995 Command_List (C).Unixsws;
998 Cmd (1 .. Command_List (C).Unixcmd'Length) :=
999 Command_List (C).Unixcmd.all;
1000 Last := Command_List (C).Unixcmd'Length;
1002 for J in Sws'Range loop
1005 Cmd (Last + 1 .. Last + Sws (J)'Length) :=
1007 Last := Last + Sws (J)'Length;
1010 Command.Unix_String := new String'(Cmd
(1 .. Last
));
1014 Command
.Params
:= Command_List
(C
).Params
;
1015 Command
.Defext
:= Command_List
(C
).Defext
;
1017 Validate_Command_Or_Option
(Command
.Name
);
1019 -- Process the switch list
1021 for S
in Command_List
(C
).Switches
'Range loop
1023 SS
: constant VMS_Data
.String_Ptr
:=
1024 Command_List
(C
).Switches
(S
);
1025 P
: Natural := SS
'First;
1026 Sw
: Item_Ptr
:= new Switch_Item
;
1028 Last_Opt
: Item_Ptr
;
1029 -- Pointer to last option
1032 -- Link new switch item into list of switches
1034 if Last_Switch
= null then
1035 Command
.Switches
:= Sw
;
1037 Last_Switch
.Next
:= Sw
;
1042 -- Process switch string, first get name
1044 while SS
(P
) /= ' ' and then SS
(P
) /= '=' loop
1048 Sw
.Name
:= new String'(SS (SS'First .. P - 1));
1050 -- Direct translation case
1052 if SS (P) = ' ' then
1053 Sw.Translation := T_Direct;
1054 Sw.Unix_String := new String'(SS
(P
+ 1 .. SS
'Last));
1055 Validate_Unix_Switch
(Sw
.Unix_String
);
1057 if SS
(P
- 1) = '>' then
1058 Sw
.Translation
:= T_Other
;
1060 elsif SS
(P
+ 1) = '`' then
1063 -- Create the inverted case (/NO ..)
1065 elsif SS
(SS
'First + 1 .. SS
'First + 2) /= "NO" then
1066 Sw
:= new Switch_Item
;
1067 Last_Switch
.Next
:= Sw
;
1071 new String'("/NO" & SS (SS'First + 1 .. P - 1));
1072 Sw.Translation := T_Direct;
1073 Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
1074 Validate_Unix_Switch (Sw.Unix_String);
1077 -- Directories translation case
1079 elsif SS (P + 1) = '*' then
1080 pragma Assert (SS (SS'Last) = '*');
1081 Sw.Translation := T_Directories;
1082 Sw.Unix_String := new String'(SS
(P
+ 2 .. SS
'Last - 1));
1083 Validate_Unix_Switch
(Sw
.Unix_String
);
1085 -- Directory translation case
1087 elsif SS
(P
+ 1) = '%' then
1088 pragma Assert
(SS
(SS
'Last) = '%');
1089 Sw
.Translation
:= T_Directory
;
1090 Sw
.Unix_String
:= new String'(SS (P + 2 .. SS'Last - 1));
1091 Validate_Unix_Switch (Sw.Unix_String);
1093 -- File translation case
1095 elsif SS (P + 1) = '@
' then
1096 pragma Assert (SS (SS'Last) = '@
');
1097 Sw.Translation := T_File;
1098 Sw.Unix_String := new String'(SS
(P
+ 2 .. SS
'Last - 1));
1099 Validate_Unix_Switch
(Sw
.Unix_String
);
1101 -- No space file translation case
1103 elsif SS
(P
+ 1) = '<' then
1104 pragma Assert
(SS
(SS
'Last) = '>');
1105 Sw
.Translation
:= T_No_Space_File
;
1106 Sw
.Unix_String
:= new String'(SS (P + 2 .. SS'Last - 1));
1107 Validate_Unix_Switch (Sw.Unix_String);
1109 -- Numeric translation case
1111 elsif SS (P + 1) = '#
' then
1112 pragma Assert (SS (SS'Last) = '#
');
1113 Sw.Translation := T_Numeric;
1114 Sw.Unix_String := new String'(SS
(P
+ 2 .. SS
'Last - 1));
1115 Validate_Unix_Switch
(Sw
.Unix_String
);
1117 -- Alphanumerplus translation case
1119 elsif SS
(P
+ 1) = '|' then
1120 pragma Assert
(SS
(SS
'Last) = '|');
1121 Sw
.Translation
:= T_Alphanumplus
;
1122 Sw
.Unix_String
:= new String'(SS (P + 2 .. SS'Last - 1));
1123 Validate_Unix_Switch (Sw.Unix_String);
1125 -- String translation case
1127 elsif SS (P + 1) = '"' then
1128 pragma Assert (SS (SS'Last) = '"');
1129 Sw.Translation := T_String;
1130 Sw.Unix_String := new String'(SS
(P
+ 2 .. SS
'Last - 1));
1131 Validate_Unix_Switch
(Sw
.Unix_String
);
1133 -- Commands translation case
1135 elsif SS
(P
+ 1) = '?' then
1136 Sw
.Translation
:= T_Commands
;
1137 Sw
.Unix_String
:= new String'(SS (P + 2 .. SS'Last));
1139 -- Options translation case
1142 Sw.Translation := T_Options;
1143 Sw.Unix_String := new String'("");
1145 P
:= P
+ 1; -- bump past =
1146 while P
<= SS
'Last loop
1148 Opt
: constant Item_Ptr
:= new Option_Item
;
1152 -- Link new option item into options list
1154 if Last_Opt
= null then
1157 Last_Opt
.Next
:= Opt
;
1162 -- Fill in fields of new option item
1165 while SS
(Q
) /= ' ' loop
1169 Opt
.Name
:= new String'(SS (P .. Q - 1));
1170 Validate_Command_Or_Option (Opt.Name);
1175 while Q <= SS'Last and then SS (Q) /= ' ' loop
1179 Opt.Unix_String := new String'(SS
(P
.. Q
- 1));
1180 Validate_Unix_Switch
(Opt
.Unix_String
);
1189 end Preprocess_Command_Data
;
1191 ----------------------
1192 -- Process_Argument --
1193 ----------------------
1195 procedure Process_Argument
(The_Command
: in out Command_Type
) is
1196 Argv
: String_Access
;
1199 function Get_Arg_End
1201 Arg_Idx
: Integer) return Integer;
1202 -- Begins looking at Arg_Idx + 1 and returns the index of the
1203 -- last character before a slash or else the index of the last
1204 -- character in the string Argv.
1210 function Get_Arg_End
1212 Arg_Idx
: Integer) return Integer
1215 for J
in Arg_Idx
+ 1 .. Argv
'Last loop
1216 if Argv
(J
) = '/' then
1224 -- Start of processing for Process_Argument
1229 -- If an argument file is open, read the next non empty line
1231 if Is_Open
(Arg_File
) then
1233 Line
: String (1 .. 256);
1237 Get_Line
(Arg_File
, Line
, Last
);
1238 exit when Last
/= 0 or else End_Of_File
(Arg_File
);
1241 -- If the end of the argument file has been reached, close it
1243 if End_Of_File
(Arg_File
) then
1246 -- If the last line was empty, return after increasing Arg_Num
1247 -- to go to the next argument on the comment line.
1250 Arg_Num
:= Arg_Num
+ 1;
1255 Argv
:= new String'(Line (1 .. Last));
1258 if Argv (1) = '@
' then
1259 Put_Line (Standard_Error, "argument file cannot contain @cmd");
1265 -- No argument file is open, get the argument on the command line
1267 Argv := new String'(Argument
(Arg_Num
));
1268 Arg_Idx
:= Argv
'First;
1270 -- Check if this is the specification of an argument file
1272 if Argv
(Arg_Idx
) = '@' then
1273 -- The first argument on the command line cannot be an argument
1279 "Cannot specify argument line before command");
1283 -- Open the file, after conversion of the name to canonical form.
1284 -- Fail if file is not found.
1287 Canonical_File_Name
: String_Access
:=
1288 To_Canonical_File_Spec
(Argv
(Arg_Idx
+ 1 .. Argv
'Last));
1290 Open
(Arg_File
, In_File
, Canonical_File_Name
.all);
1291 Free
(Canonical_File_Name
);
1296 Put
(Standard_Error
, "Cannot open argument file """);
1297 Put
(Standard_Error
, Argv
(Arg_Idx
+ 1 .. Argv
'Last));
1298 Put_Line
(Standard_Error
, """");
1304 <<Tryagain_After_Coalesce
>>
1307 Next_Arg_Idx
: Integer;
1308 Arg
: String_Access
;
1311 Next_Arg_Idx
:= Get_Arg_End
(Argv
.all, Arg_Idx
);
1312 Arg
:= new String'(Argv (Arg_Idx .. Next_Arg_Idx));
1314 -- The first one must be a command name
1316 if Arg_Num = 1 and then Arg_Idx = Argv'First then
1317 Command := Matching_Name (Arg.all, Commands);
1319 if Command = null then
1323 The_Command := Command.Command;
1324 Output_File_Expected := False;
1326 -- Give usage information if only command given
1328 if Argument_Count = 1
1329 and then Next_Arg_Idx = Argv'Last
1334 ("List of available qualifiers and options");
1337 Put (Command.Usage.all);
1339 Put_Line (Command.Unix_String.all);
1342 Sw : Item_Ptr := Command.Switches;
1345 while Sw /= null loop
1349 case Sw.Translation is
1353 Put_Line (Sw.Unix_String.all &
1358 Put_Line (Sw.Unix_String.all);
1360 when T_Directories =>
1361 Put ("=(direc,direc,..direc)");
1363 Put (Sw.Unix_String.all);
1365 Put (Sw.Unix_String.all);
1366 Put_Line (" direc ...");
1371 Put (Sw.Unix_String.all);
1373 if Sw.Unix_String (Sw.Unix_String'Last)
1379 Put_Line ("directory ");
1381 when T_File | T_No_Space_File =>
1384 Put (Sw.Unix_String.all);
1386 if Sw.Translation = T_File
1387 and then Sw.Unix_String
1388 (Sw.Unix_String'Last) /= '='
1400 (Sw.Unix_String'First) = '`
'
1403 (Sw.Unix_String'First + 1
1404 .. Sw.Unix_String'Last));
1406 Put (Sw.Unix_String.all);
1411 when T_Alphanumplus =>
1416 (Sw.Unix_String'First) = '`
'
1419 (Sw.Unix_String'First + 1
1420 .. Sw.Unix_String'Last));
1422 Put (Sw.Unix_String.all);
1434 Put (Sw.Unix_String.all);
1437 (Sw.Unix_String'Last) /= '='
1446 Put (" (switches for ");
1448 (Sw.Unix_String'First + 7
1449 .. Sw.Unix_String'Last));
1453 (Sw.Unix_String'First
1454 .. Sw.Unix_String'First + 5));
1455 Put_Line (" switches");
1459 Opt : Item_Ptr := Sw.Options;
1462 Put_Line ("=(option,option..)");
1464 while Opt /= null loop
1468 if Opt = Sw.Options then
1473 Put_Line (Opt.Unix_String.all);
1487 -- Special handling for internal debugging switch /?
1489 elsif Arg.all = "/?" then
1490 Display_Command := True;
1491 Output_File_Expected := False;
1493 -- Special handling of internal option /KEEP_TEMPORARY_FILES
1495 elsif Arg'Length >= 7
1496 and then Matching_Name
1497 (Arg.all, Keep_Temps_Option, True) /= null
1499 Opt.Keep_Temporary_Files := True;
1501 -- Copy -switch unchanged, as well as +rule
1503 elsif Arg (Arg'First) = '-' or else Arg (Arg'First) = '+' then
1507 -- Set Output_File_Expected for the next argument
1509 Output_File_Expected :=
1510 Arg.all = "-o" and then The_Command = Link;
1512 -- Copy quoted switch with quotes stripped
1514 elsif Arg (Arg'First) = '"' then
1515 if Arg (Arg'Last) /= '"' then
1516 Put (Standard_Error, "misquoted argument: ");
1517 Put_Line (Standard_Error, Arg.all);
1518 Errors := Errors + 1;
1522 Place (Arg (Arg'First + 1 .. Arg'Last - 1));
1525 Output_File_Expected := False;
1527 -- Parameter Argument
1529 elsif Arg (Arg'First) /= '/'
1530 and then Make_Commands_Active = null
1532 Param_Count := Param_Count + 1;
1534 if Param_Count <= Command.Params'Length then
1536 case Command.Params (Param_Count) is
1538 when File | Optional_File =>
1540 Normal_File : constant String_Access :=
1541 To_Canonical_File_Spec
1546 Place_Lower (Normal_File.all);
1548 if Is_Extensionless (Normal_File.all)
1549 and then Command.Defext /= " "
1552 Place (Command.Defext);
1556 when Unlimited_Files =>
1558 Normal_File : constant String_Access :=
1559 To_Canonical_File_Spec
1562 File_Is_Wild : Boolean := False;
1563 File_List : String_Access_List_Access;
1566 for J in Arg'Range loop
1568 or else Arg (J) = '%'
1570 File_Is_Wild := True;
1574 if File_Is_Wild then
1575 File_List := To_Canonical_File_List
1578 for J in File_List.all'Range loop
1580 Place_Lower (File_List.all (J).all);
1585 Place_Lower (Normal_File.all);
1587 -- Add extension if not present, except after
1590 if Is_Extensionless (Normal_File.all)
1591 and then Command.Defext /= " "
1592 and then not Output_File_Expected
1595 Place (Command.Defext);
1599 Param_Count := Param_Count - 1;
1606 when Unlimited_As_Is =>
1609 Param_Count := Param_Count - 1;
1611 when Files_Or_Wildcard =>
1613 -- Remove spaces from a comma separated list
1614 -- of file names and adjust control variables
1617 while Arg_Num < Argument_Count and then
1618 (Argv (Argv'Last) = ',' xor
1619 Argument (Arg_Num + 1)
1620 (Argument (Arg_Num + 1)'First) = ',')
1623 (Argv
.all & Argument
(Arg_Num
+ 1));
1624 Arg_Num
:= Arg_Num
+ 1;
1625 Arg_Idx
:= Argv
'First;
1627 Get_Arg_End
(Argv
.all, Arg_Idx
);
1629 (Argv (Arg_Idx .. Next_Arg_Idx));
1632 -- Parse the comma separated list of VMS
1633 -- filenames and place them on the command
1634 -- line as space separated Unix style
1635 -- filenames. Lower case and add default
1636 -- extension as appropriate.
1639 Arg1_Idx : Integer := Arg'First;
1641 function Get_Arg1_End
1643 Arg_Idx : Integer) return Integer;
1644 -- Begins looking at Arg_Idx + 1 and
1645 -- returns the index of the last character
1646 -- before a comma or else the index of the
1647 -- last character in the string Arg.
1653 function Get_Arg1_End
1655 Arg_Idx : Integer) return Integer
1658 for J in Arg_Idx + 1 .. Arg'Last loop
1659 if Arg (J) = ',' then
1672 Get_Arg1_End (Arg.all, Arg1_Idx);
1676 Arg (Arg1_Idx .. Next_Arg1_Idx);
1679 constant String_Access :=
1680 To_Canonical_File_Spec (Arg1);
1684 Place_Lower (Normal_File.all);
1686 if Is_Extensionless (Normal_File.all)
1687 and then Command.Defext /= " "
1690 Place (Command.Defext);
1693 Arg1_Idx := Next_Arg1_Idx + 1;
1696 exit when Arg1_Idx > Arg'Last;
1698 -- Don't allow two or more commas in
1701 if Arg (Arg1_Idx) = ',' then
1702 Arg1_Idx := Arg1_Idx + 1;
1703 if Arg1_Idx > Arg'Last or else
1704 Arg (Arg1_Idx) = ','
1708 "Malformed Parameter: " &
1710 Put (Standard_Error, "usage: ");
1711 Put_Line (Standard_Error,
1722 -- Reset Output_File_Expected, in case it was True
1724 Output_File_Expected := False;
1726 -- Qualifier argument
1729 Output_File_Expected := False;
1731 Cargs := Command.Name.all = "COMPILE";
1733 -- This code is too heavily nested, should be
1734 -- separated out as separate subprogram ???
1740 Endp : Natural := 0; -- avoid warning!
1745 while SwP < Arg'Last
1746 and then Arg (SwP + 1) /= '='
1751 -- At this point, the switch name is in
1752 -- Arg (Arg'First..SwP) and if that is not the
1753 -- whole switch, then there is an equal sign at
1754 -- Arg (SwP + 1) and the rest of Arg is what comes
1755 -- after the equal sign.
1757 -- If make commands are active, see if we have
1758 -- another COMMANDS_TRANSLATION switch belonging
1761 if Make_Commands_Active /= null then
1764 (Arg (Arg'First .. SwP),
1769 and then Sw.Translation = T_Commands
1776 (Arg (Arg'First .. SwP),
1777 Make_Commands_Active.Switches,
1781 -- For case of GNAT MAKE or CHOP, if we cannot
1782 -- find the switch, then see if it is a
1783 -- recognized compiler switch instead, and if
1784 -- so process the compiler switch.
1786 elsif Command.Name.all = "MAKE"
1787 or else Command.Name.all = "CHOP" then
1790 (Arg (Arg'First .. SwP),
1797 (Arg (Arg'First .. SwP),
1799 ("COMPILE", Commands).Switches,
1803 -- For all other cases, just search the relevant
1809 (Arg (Arg'First .. SwP),
1813 -- Special case for GNAT COMPILE /UNCHECKED...
1814 -- because the corresponding switch --unchecked... is
1815 -- for gnatmake, not for the compiler.
1818 and then Sw.Name.all = "/UNCHECKED_SHARED_LIB_IMPORTS"
1826 and then Sw.Name /= null
1828 (Sw.Name.all = "/PROJECT_FILE" or else
1829 Sw.Name.all = "/MESSAGES_PROJECT_FILE" or else
1830 Sw.Name.all = "/EXTERNAL_REFERENCE")
1835 case Sw.Translation is
1837 Place_Unix_Switches (Sw.Unix_String);
1840 and then Arg (SwP + 1) = '='
1842 Put (Standard_Error,
1843 "qualifier options ignored: ");
1844 Put_Line (Standard_Error, Arg.all);
1847 when T_Directories =>
1848 if SwP + 1 > Arg'Last then
1849 Put (Standard_Error,
1850 "missing directories for: ");
1851 Put_Line (Standard_Error, Arg.all);
1852 Errors := Errors + 1;
1854 elsif Arg (SwP + 2) /= '(' then
1858 elsif Arg (Arg'Last) /= ')' then
1860 -- Remove spaces from a comma separated
1861 -- list of file names and adjust
1862 -- control variables accordingly.
1864 if Arg_Num < Argument_Count and then
1865 (Argv (Argv'Last) = ',' xor
1866 Argument (Arg_Num + 1)
1867 (Argument (Arg_Num + 1)'First) = ',')
1870 new String'(Argv
.all
1873 Arg_Num
:= Arg_Num
+ 1;
1874 Arg_Idx
:= Argv
'First;
1876 Get_Arg_End
(Argv
.all, Arg_Idx
);
1878 new String'(Argv (Arg_Idx .. Next_Arg_Idx));
1879 goto Tryagain_After_Coalesce;
1882 Put (Standard_Error,
1883 "incorrectly parenthesized " &
1884 "or malformed argument: ");
1885 Put_Line (Standard_Error, Arg.all);
1886 Errors := Errors + 1;
1890 Endp := Arg'Last - 1;
1893 while SwP <= Endp loop
1895 Dir_Is_Wild : Boolean := False;
1896 Dir_Maybe_Is_Wild : Boolean := False;
1898 Dir_List : String_Access_List_Access;
1904 and then Arg (P2 + 1) /= ','
1906 -- A wildcard directory spec on VMS will
1907 -- contain either * or % or ...
1909 if Arg (P2) = '*' then
1910 Dir_Is_Wild := True;
1912 elsif Arg (P2) = '%' then
1913 Dir_Is_Wild := True;
1915 elsif Dir_Maybe_Is_Wild
1916 and then Arg (P2) = '.'
1917 and then Arg (P2 + 1) = '.'
1919 Dir_Is_Wild := True;
1920 Dir_Maybe_Is_Wild := False;
1922 elsif Dir_Maybe_Is_Wild then
1923 Dir_Maybe_Is_Wild := False;
1925 elsif Arg (P2) = '.'
1926 and then Arg (P2 + 1) = '.'
1928 Dir_Maybe_Is_Wild := True;
1937 To_Canonical_File_List
1938 (Arg (SwP .. P2), True);
1940 for J in Dir_List.all'Range loop
1941 Place_Unix_Switches (Sw.Unix_String);
1942 Place_Lower (Dir_List.all (J).all);
1946 Place_Unix_Switches (Sw.Unix_String);
1948 (To_Canonical_Dir_Spec
1949 (Arg (SwP .. P2), False).all);
1957 if SwP + 1 > Arg'Last then
1958 Put (Standard_Error,
1959 "missing directory for: ");
1960 Put_Line (Standard_Error, Arg.all);
1961 Errors := Errors + 1;
1964 Place_Unix_Switches (Sw.Unix_String);
1966 -- Some switches end in "=", no space here
1969 (Sw.Unix_String'Last) /= '='
1975 (To_Canonical_Dir_Spec
1976 (Arg (SwP + 2 .. Arg'Last), False).all);
1979 when T_File | T_No_Space_File =>
1980 if SwP + 2 > Arg'Last then
1981 Put (Standard_Error, "missing file for: ");
1982 Put_Line (Standard_Error, Arg.all);
1983 Errors := Errors + 1;
1986 Place_Unix_Switches (Sw.Unix_String);
1988 -- Some switches end in "=", no space here.
1990 if Sw.Translation = T_File
1991 and then Sw.Unix_String
1992 (Sw.Unix_String'Last) /= '='
1998 (To_Canonical_File_Spec
1999 (Arg (SwP + 2 .. Arg'Last)).all);
2003 if OK_Integer (Arg (SwP + 2 .. Arg'Last)) then
2004 Place_Unix_Switches (Sw.Unix_String);
2005 Place (Arg (SwP + 2 .. Arg'Last));
2008 Put (Standard_Error, "argument for ");
2009 Put (Standard_Error, Sw.Name.all);
2010 Put_Line (Standard_Error, " must be numeric");
2011 Errors := Errors + 1;
2014 when T_Alphanumplus =>
2015 if OK_Alphanumerplus
2016 (Arg (SwP + 2 .. Arg'Last))
2018 Place_Unix_Switches (Sw.Unix_String);
2019 Place (Arg (SwP + 2 .. Arg'Last));
2022 Put (Standard_Error, "argument for ");
2023 Put (Standard_Error, Sw.Name.all);
2024 Put_Line (Standard_Error,
2025 " must be alphanumeric");
2026 Errors := Errors + 1;
2031 -- A String value must be extended to the end of
2032 -- the Argv, otherwise strings like "foo/bar" get
2033 -- split at the slash.
2035 -- The beginning and ending of the string are
2036 -- flagged with embedded nulls which are removed
2037 -- when building the Spawn call. Nulls are use
2038 -- because they won't show up in a /? output.
2039 -- Quotes aren't used because that would make it
2040 -- difficult to embed them.
2042 Place_Unix_Switches (Sw.Unix_String);
2044 if Next_Arg_Idx /= Argv'Last then
2045 Next_Arg_Idx := Argv'Last;
2047 new String'(Argv
(Arg_Idx
.. Next_Arg_Idx
));
2050 while SwP
< Arg
'Last
2051 and then Arg
(SwP
+ 1) /= '='
2058 Place
(Arg
(SwP
+ 2 .. Arg
'Last));
2063 -- Output -largs/-bargs/-cargs
2066 Place
(Sw
.Unix_String
2067 (Sw
.Unix_String
'First ..
2068 Sw
.Unix_String
'First + 5));
2071 (Sw
.Unix_String
'First + 7 ..
2072 Sw
.Unix_String
'Last) = "MAKE"
2074 Make_Commands_Active
:= null;
2077 -- Set source of new commands, also setting this
2078 -- non-null indicates that we are in the special
2079 -- commands mode for processing the -xargs case.
2081 Make_Commands_Active
:=
2084 (Sw
.Unix_String
'First + 7 ..
2085 Sw
.Unix_String
'Last),
2090 if SwP
+ 1 > Arg
'Last then
2091 Place_Unix_Switches
(Sw
.Options
.Unix_String
);
2094 elsif Arg
(SwP
+ 2) /= '(' then
2098 elsif Arg
(Arg
'Last) /= ')' then
2099 Put
(Standard_Error
,
2100 "incorrectly parenthesized argument: ");
2101 Put_Line
(Standard_Error
, Arg
.all);
2102 Errors
:= Errors
+ 1;
2107 Endp
:= Arg
'Last - 1;
2110 while SwP
<= Endp
loop
2113 and then Arg
(P2
+ 1) /= ','
2118 -- Option name is in Arg (SwP .. P2)
2120 Opt
:= Matching_Name
(Arg
(SwP
.. P2
),
2124 Place_Unix_Switches
(Opt
.Unix_String
);
2132 (new String'(Sw.Unix_String.all & Arg.all));
2139 Arg_Idx := Next_Arg_Idx + 1;
2142 exit when Arg_Idx > Argv'Last;
2146 if not Is_Open (Arg_File) then
2147 Arg_Num := Arg_Num + 1;
2149 end Process_Argument;
2151 --------------------
2152 -- Process_Buffer --
2153 --------------------
2155 procedure Process_Buffer (S : String) is
2157 Inside_Nul : Boolean := False;
2158 Arg : String (1 .. 1024);
2163 while P1 <= S'Last and then S (P1) = ' ' loop
2168 Arg (Arg_Ctr) := S (P1);
2170 while P1 <= S'Last loop
2171 if S (P1) = ASCII.NUL then
2173 Inside_Nul := False;
2179 if S (P1) = ' ' and then not Inside_Nul then
2181 Arg_Ctr := Arg_Ctr + 1;
2182 Arg (Arg_Ctr) := S (P1);
2185 Last_Switches.Increment_Last;
2189 and then (S (P2 + 1) /= ' ' or else
2193 Arg_Ctr := Arg_Ctr + 1;
2194 Arg (Arg_Ctr) := S (P2);
2195 if S (P2) = ASCII.NUL then
2196 Arg_Ctr := Arg_Ctr - 1;
2199 Inside_Nul := False;
2206 Last_Switches.Table (Last_Switches.Last) :=
2207 new String'(String (Arg
(1 .. Arg_Ctr
)));
2210 exit when P1
> S
'Last;
2213 Arg
(Arg_Ctr
) := S
(P1
);
2218 --------------------------------
2219 -- Validate_Command_Or_Option --
2220 --------------------------------
2222 procedure Validate_Command_Or_Option
(N
: VMS_Data
.String_Ptr
) is
2224 pragma Assert
(N
'Length > 0);
2226 for J
in N
'Range loop
2228 pragma Assert
(N
(J
- 1) /= '_');
2231 pragma Assert
(Is_Upper
(N
(J
)) or else Is_Digit
(N
(J
)));
2235 end Validate_Command_Or_Option
;
2237 --------------------------
2238 -- Validate_Unix_Switch --
2239 --------------------------
2241 procedure Validate_Unix_Switch
(S
: VMS_Data
.String_Ptr
) is
2243 if S
(S
'First) = '`' then
2247 pragma Assert
(S
(S
'First) = '-' or else S
(S
'First) = '!');
2249 for J
in S
'First + 1 .. S
'Last loop
2250 pragma Assert
(S
(J
) /= ' ');
2253 pragma Assert
(S
(J
- 1) = ',' and then S
(J
+ 1) = '-');
2257 end Validate_Unix_Switch
;
2259 --------------------
2260 -- VMS_Conversion --
2261 --------------------
2263 procedure VMS_Conversion
(The_Command
: out Command_Type
) is
2264 Result
: Command_Type
:= Undefined
;
2265 Result_Set
: Boolean := False;
2270 -- First we must preprocess the string form of the command and options
2271 -- list into the internal form that we use.
2273 Preprocess_Command_Data
;
2275 -- If no parameters, give complete list of commands
2277 if Argument_Count
= 0 then
2280 Put_Line
("List of available commands");
2283 while Commands
/= null loop
2285 -- No usage for GNAT SYNC
2287 if Commands
.Command
/= Sync
then
2288 Put
(Commands
.Usage
.all);
2290 Put_Line
(Commands
.Unix_String
.all);
2293 Commands
:= Commands
.Next
;
2299 -- Loop through arguments
2302 while Arg_Num
<= Argument_Count
loop
2303 Process_Argument
(Result
);
2305 if not Result_Set
then
2306 The_Command
:= Result
;
2311 -- Gross error checking that the number of parameters is correct.
2312 -- Not applicable to Unlimited_Files parameters.
2314 if (Param_Count
= Command
.Params
'Length - 1
2315 and then Command
.Params
(Param_Count
+ 1) = Unlimited_Files
)
2316 or else Param_Count
<= Command
.Params
'Length
2321 Put_Line
(Standard_Error
,
2322 "Parameter count of "
2323 & Integer'Image (Param_Count
)
2324 & " not equal to expected "
2325 & Integer'Image (Command
.Params
'Length));
2326 Put
(Standard_Error
, "usage: ");
2327 Put_Line
(Standard_Error
, Command
.Usage
.all);
2328 Errors
:= Errors
+ 1;
2334 -- Prepare arguments for a call to spawn, filtering out
2335 -- embedded nulls place there to delineate strings.
2337 Process_Buffer
(String (Buffer
.Table
(1 .. Buffer
.Last
)));
2339 if Cargs_Buffer
.Last
> 1 then
2340 Last_Switches
.Append
(new String'("-cargs"));
2342 (String (Cargs_Buffer.Table (1 .. Cargs_Buffer.Last)));