1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 1996-2001 Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
27 ------------------------------------------------------------------------------
29 with Ada.Characters.Handling; use Ada.Characters.Handling;
30 with Ada.Command_Line; use Ada.Command_Line;
31 with Ada.Text_IO; use Ada.Text_IO;
33 with Osint; use Osint;
34 with Sdefault; use Sdefault;
35 with Hostparm; use Hostparm;
36 -- Used to determine if we are in VMS or not for error message purposes
39 with GNAT.OS_Lib; use GNAT.OS_Lib;
44 pragma Ident (Gnatvsn.Gnat_Version_String);
50 -- The switch tables contain an entry for each switch recognized by the
51 -- command processor. The syntax of entries is as follows:
53 -- SWITCH_STRING ::= "/ command-qualifier-name TRANSLATION"
57 -- | DIRECTORIES_TRANSLATION
59 -- | NUMERIC_TRANSLATION
60 -- | STRING_TRANSLATION
61 -- | OPTIONS_TRANSLATION
62 -- | COMMANDS_TRANSLATION
63 -- | ALPHANUMPLUS_TRANSLATION
64 -- | OTHER_TRANSLATION
66 -- DIRECT_TRANSLATION ::= space UNIX_SWITCHES
67 -- DIRECTORIES_TRANSLATION ::= =* UNIX_SWITCH *
68 -- DIRECTORY_TRANSLATION ::= =% UNIX_SWITCH %
69 -- FILE_TRANSLATION ::= =@ UNIX_SWITCH @
70 -- NUMERIC_TRANSLATION ::= =# UNIX_SWITCH # | # number #
71 -- STRING_TRANSLATION ::= =" UNIX_SWITCH "
72 -- OPTIONS_TRANSLATION ::= =OPTION {space OPTION}
73 -- COMMANDS_TRANSLATION ::= =? ARGS space command-name
74 -- ALPHANUMPLUS_TRANSLATION ::= =| UNIX_SWITCH |
76 -- UNIX_SWITCHES ::= UNIX_SWITCH {, UNIX_SWITCH}
78 -- UNIX_SWITCH ::= unix-switch-string | !unix-switch-string | `string'
80 -- OPTION ::= option-name space UNIX_SWITCHES
82 -- ARGS ::= -cargs | -bargs | -largs
84 -- Here command-qual is the name of the switch recognized by the GNATCmd.
85 -- This is always given in upper case in the templates, although in the
86 -- actual commands, either upper or lower case is allowed.
88 -- The unix-switch-string always starts with a minus, and has no commas
89 -- or spaces in it. Case is significant in the unix switch string. If a
90 -- unix switch string is preceded by the not sign (!) it means that the
91 -- effect of the corresponding command qualifer is to remove any previous
92 -- occurrence of the given switch in the command line.
94 -- The DIRECTORIES_TRANSLATION format is used where a list of directories
95 -- is given. This possible corresponding formats recognized by GNATCmd are
96 -- as shown by the following example for the case of PATH
99 -- PATH=(direc,direc,direc,direc)
101 -- When more than one directory is present for the DIRECTORIES case, then
102 -- multiple instances of the corresponding unix switch are generated,
103 -- with the file name being substituted for the occurrence of *.
105 -- The FILE_TRANSLATION format is similar except that only a single
106 -- file is allowed, not a list of files, and only one unix switch is
107 -- generated as a result.
109 -- The NUMERIC_TRANSLATION format is similar to the FILE_TRANSLATION case
110 -- except that the parameter is a decimal integer in the range 0 to 999.
112 -- For the OPTIONS_TRANSLATION case, GNATCmd similarly permits one or
113 -- more options to appear (although only in some cases does the use of
114 -- multiple options make logical sense). For example, taking the
115 -- case of ERRORS for GCC, the following are all allowed:
118 -- /ERRORS=(FULL,VERBOSE)
119 -- /ERRORS=(BRIEF IMMEDIATE)
121 -- If no option is provided (e.g. just /ERRORS is written), then the
122 -- first option in the list is the default option. For /ERRORS this
123 -- is NORMAL, so /ERRORS with no option is equivalent to /ERRORS=NORMAL.
125 -- The COMMANDS_TRANSLATION case is only used for gnatmake, to correspond
126 -- to the use of -cargs, -bargs and -largs (the ARGS string as indicated
127 -- is one of these three possibilities). The name given by COMMAND is the
128 -- corresponding command name to be used to interprete the switches to be
129 -- passed on. Switches of this type set modes, e.g. /COMPILER_QUALIFIERS
130 -- sets the mode so that all subsequent switches, up to another switch
131 -- with COMMANDS_TRANSLATION apply to the corresponding commands issued
132 -- by the make utility. For example
134 -- /COMPILER_QUALIFIERS /LIST /BINDER_QUALIFIERS /MAIN
135 -- /COMPILER_QUALIFIERS /NOLIST /COMPILE_CHECKS=SYNTAX
137 -- Clearly these switches must come at the end of the list of switches
138 -- since all subsequent switches apply to an issued command.
140 -- For the DIRECT_TRANSLATION case, an implicit additional entry is
141 -- created by prepending NO to the name of the qualifer, and then
142 -- inverting the sense of the UNIX_SWITCHES string. For example,
147 -- An implicit entry is created:
151 -- In the case where, a ! is already present, inverting the sense of the
152 -- switch means removing it.
155 -- A synonym to shorten the table
157 type String_Ptr is access constant String;
158 -- String pointer type used throughout
160 type Switches is array (Natural range <>) of String_Ptr;
161 -- Type used for array of swtiches
163 type Switches_Ptr is access constant Switches;
165 --------------------------------
166 -- Switches for project files --
167 --------------------------------
169 S_Ext_Ref : aliased constant S := "/EXTERNAL_REFERENCE=" & '"' &
172 S_Project_File : aliased constant S := "/PROJECT_FILE=*" &
174 S_Project_Verb : aliased constant S := "/PROJECT_FILE_VERBOSITY=" &
182 ----------------------------
183 -- Switches for GNAT BIND --
184 ----------------------------
186 S_Bind_Bind : aliased constant S := "/BIND_FILE=" &
192 S_Bind_Build : aliased constant S := "/BUILD_LIBRARY=|" &
195 S_Bind_Current : aliased constant S := "/CURRENT_DIRECTORY " &
198 S_Bind_Debug : aliased constant S := "/DEBUG=" &
214 S_Bind_DebugX : aliased constant S := "/NODEBUG " &
217 S_Bind_Elab : aliased constant S := "/ELABORATION_DEPENDENCIES " &
220 S_Bind_Error : aliased constant S := "/ERROR_LIMIT=#" &
223 S_Bind_Library : aliased constant S := "/LIBRARY_SEARCH=*" &
226 S_Bind_Linker : aliased constant S := "/LINKER_OPTION_LIST " &
229 S_Bind_Main : aliased constant S := "/MAIN " &
232 S_Bind_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
235 S_Bind_Nostlib : aliased constant S := "/NOSTD_LIBRARIES " &
238 S_Bind_Object : aliased constant S := "/OBJECT_LIST " &
241 S_Bind_Order : aliased constant S := "/ORDER_OF_ELABORATION " &
244 S_Bind_Output : aliased constant S := "/OUTPUT=@" &
247 S_Bind_OutputX : aliased constant S := "/NOOUTPUT " &
250 S_Bind_Pess : aliased constant S := "/PESSIMISTIC_ELABORATION " &
253 S_Bind_Read : aliased constant S := "/READ_SOURCES=" &
261 S_Bind_ReadX : aliased constant S := "/NOREAD_SOURCES " &
264 S_Bind_Rename : aliased constant S := "/RENAME_MAIN " &
267 S_Bind_Report : aliased constant S := "/REPORT_ERRORS=" &
275 S_Bind_ReportX : aliased constant S := "/NOREPORT_ERRORS " &
278 S_Bind_Search : aliased constant S := "/SEARCH=*" &
281 S_Bind_Shared : aliased constant S := "/SHARED " &
284 S_Bind_Source : aliased constant S := "/SOURCE_SEARCH=*" &
287 S_Bind_Time : aliased constant S := "/TIME_STAMP_CHECK " &
290 S_Bind_Verbose : aliased constant S := "/VERBOSE " &
293 S_Bind_Warn : aliased constant S := "/WARNINGS=" &
301 S_Bind_WarnX : aliased constant S := "/NOWARNINGS " &
304 Bind_Switches : aliased constant Switches := (
306 S_Bind_Build 'Access,
307 S_Bind_Current 'Access,
308 S_Bind_Debug 'Access,
309 S_Bind_DebugX 'Access,
311 S_Bind_Error 'Access,
313 S_Bind_Library 'Access,
314 S_Bind_Linker 'Access,
316 S_Bind_Nostinc 'Access,
317 S_Bind_Nostlib 'Access,
318 S_Bind_Object 'Access,
319 S_Bind_Order 'Access,
320 S_Bind_Output 'Access,
321 S_Bind_OutputX 'Access,
323 S_Project_File 'Access,
324 S_Project_Verb 'Access,
326 S_Bind_ReadX 'Access,
327 S_Bind_Rename 'Access,
328 S_Bind_Report 'Access,
329 S_Bind_ReportX 'Access,
330 S_Bind_Search 'Access,
331 S_Bind_Shared 'Access,
332 S_Bind_Source 'Access,
334 S_Bind_Verbose 'Access,
336 S_Bind_WarnX 'Access);
338 ----------------------------
339 -- Switches for GNAT CHOP --
340 ----------------------------
342 S_Chop_Comp : aliased constant S := "/COMPILATION " &
345 S_Chop_File : aliased constant S := "/FILE_NAME_MAX_LENGTH=#" &
348 S_Chop_Help : aliased constant S := "/HELP " &
351 S_Chop_Over : aliased constant S := "/OVERWRITE " &
354 S_Chop_Pres : aliased constant S := "/PRESERVE " &
357 S_Chop_Quiet : aliased constant S := "/QUIET " &
360 S_Chop_Ref : aliased constant S := "/REFERENCE " &
363 S_Chop_Verb : aliased constant S := "/VERBOSE " &
366 Chop_Switches : aliased constant Switches := (
372 S_Chop_Quiet 'Access,
374 S_Chop_Verb 'Access);
376 -------------------------------
377 -- Switches for GNAT COMPILE --
378 -------------------------------
380 S_GCC_Ada_83 : aliased constant S := "/83 " &
383 S_GCC_Ada_95 : aliased constant S := "/95 " &
386 S_GCC_Asm : aliased constant S := "/ASM " &
389 S_GCC_Checks : aliased constant S := "/CHECKS=" &
391 "-gnato,!-gnatE,!-gnatp " &
403 S_GCC_ChecksX : aliased constant S := "/NOCHECKS " &
404 "-gnatp,!-gnato,!-gnatE";
406 S_GCC_Compres : aliased constant S := "/COMPRESS_NAMES " &
409 S_GCC_Current : aliased constant S := "/CURRENT_DIRECTORY " &
412 S_GCC_Debug : aliased constant S := "/DEBUG=" &
426 S_GCC_DebugX : aliased constant S := "/NODEBUG " &
429 S_GCC_Dist : aliased constant S := "/DISTRIBUTION_STUBS=" &
435 S_GCC_DistX : aliased constant S := "/NODISTRIBUTION_STUBS " &
438 S_GCC_Error : aliased constant S := "/ERROR_LIMIT=#" &
441 S_GCC_ErrorX : aliased constant S := "/NOERROR_LIMIT " &
444 S_GCC_Expand : aliased constant S := "/EXPAND_SOURCE " &
447 S_GCC_Extend : aliased constant S := "/EXTENSIONS_ALLOWED " &
450 S_GCC_File : aliased constant S := "/FILE_NAME_MAX_LENGTH=#" &
453 S_GCC_Force : aliased constant S := "/FORCE_ALI " &
456 S_GCC_Ident : aliased constant S := "/IDENTIFIER_CHARACTER_SET=" &
478 S_GCC_IdentX : aliased constant S := "/NOIDENTIFIER_CHARACTER_SET " &
481 S_GCC_Inline : aliased constant S := "/INLINE=" &
487 S_GCC_InlineX : aliased constant S := "/NOINLINE " &
490 S_GCC_List : aliased constant S := "/LIST " &
493 S_GCC_Noload : aliased constant S := "/NOLOAD " &
496 S_GCC_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
499 S_GCC_Opt : aliased constant S := "/OPTIMIZE=" &
501 "-O2,!-O0,!-O1,!-O3 " &
503 "-O0,!-O1,!-O2,!-O3 " &
505 "-O1,!-O0,!-O2,!-O3 " &
507 "-O1,!-O0,!-O2,!-O3 " &
511 "-O3,!-O0,!-O1,!-O2";
513 S_GCC_OptX : aliased constant S := "/NOOPTIMIZE " &
514 "-O0,!-O1,!-O2,!-O3";
516 S_GCC_Report : aliased constant S := "/REPORT_ERRORS=" &
528 S_GCC_ReportX : aliased constant S := "/NOREPORT_ERRORS " &
531 S_GCC_Repinfo : aliased constant S := "/REPRESENTATION_INFO=" &
543 S_GCC_RepinfX : aliased constant S := "/NOREPRESENTATION_INFO " &
546 S_GCC_Search : aliased constant S := "/SEARCH=*" &
549 S_GCC_Style : aliased constant S := "/STYLE_CHECKS=" &
594 "ORDERED_SUBPROGRAMS " &
607 S_GCC_StyleX : aliased constant S := "/NOSTYLE_CHECKS " &
610 S_GCC_Syntax : aliased constant S := "/SYNTAX_ONLY " &
613 S_GCC_Trace : aliased constant S := "/TRACE_UNITS " &
616 S_GCC_Tree : aliased constant S := "/TREE_OUTPUT " &
619 S_GCC_Trys : aliased constant S := "/TRY_SEMANTICS " &
622 S_GCC_Units : aliased constant S := "/UNITS_LIST " &
625 S_GCC_Unique : aliased constant S := "/UNIQUE_ERROR_TAG " &
628 S_GCC_Upcase : aliased constant S := "/UPPERCASE_EXTERNALS " &
631 S_GCC_Valid : aliased constant S := "/VALIDITY_CHECKING=" &
673 S_GCC_Verbose : aliased constant S := "/VERBOSE " &
676 S_GCC_Warn : aliased constant S := "/WARNINGS=" &
678 "!-gnatws,!-gnatwe " &
697 "NOIMPLEMENTATION " &
720 S_GCC_WarnX : aliased constant S := "/NOWARNINGS " &
723 S_GCC_Wide : aliased constant S := "/WIDE_CHARACTER_ENCODING=" &
739 S_GCC_WideX : aliased constant S := "/NOWIDE_CHARACTER_ENCODING " &
742 S_GCC_Xdebug : aliased constant S := "/XDEBUG " &
745 S_GCC_Xref : aliased constant S := "/XREF=" &
751 GCC_Switches : aliased constant Switches := (
752 S_GCC_Ada_83 'Access,
753 S_GCC_Ada_95 'Access,
755 S_GCC_Checks 'Access,
756 S_GCC_ChecksX 'Access,
757 S_GCC_Compres 'Access,
758 S_GCC_Current 'Access,
760 S_GCC_DebugX 'Access,
764 S_GCC_ErrorX 'Access,
765 S_GCC_Expand 'Access,
766 S_GCC_Extend 'Access,
770 S_GCC_IdentX 'Access,
771 S_GCC_Inline 'Access,
772 S_GCC_InlineX 'Access,
774 S_GCC_Noload 'Access,
775 S_GCC_Nostinc 'Access,
778 S_GCC_Report 'Access,
779 S_GCC_ReportX 'Access,
780 S_GCC_Repinfo 'Access,
781 S_GCC_RepinfX 'Access,
782 S_GCC_Search 'Access,
784 S_GCC_StyleX 'Access,
785 S_GCC_Syntax 'Access,
790 S_GCC_Unique 'Access,
791 S_GCC_Upcase 'Access,
793 S_GCC_Verbose 'Access,
798 S_GCC_Xdebug 'Access,
801 ----------------------------
802 -- Switches for GNAT ELIM --
803 ----------------------------
805 S_Elim_All : aliased constant S := "/ALL " &
808 S_Elim_Miss : aliased constant S := "/MISSED " &
811 S_Elim_Verb : aliased constant S := "/VERBOSE " &
814 Elim_Switches : aliased constant Switches := (
817 S_Elim_Verb 'Access);
819 ----------------------------
820 -- Switches for GNAT FIND --
821 ----------------------------
823 S_Find_All : aliased constant S := "/ALL_FILES " &
826 S_Find_Expr : aliased constant S := "/EXPRESSIONS " &
829 S_Find_Full : aliased constant S := "/FULL_PATHNAME " &
832 S_Find_Ignore : aliased constant S := "/IGNORE_LOCALS " &
835 S_Find_Object : aliased constant S := "/OBJECT_SEARCH=*" &
838 S_Find_Print : aliased constant S := "/PRINT_LINES " &
841 S_Find_Project : aliased constant S := "/PROJECT=@" &
844 S_Find_Ref : aliased constant S := "/REFERENCES " &
847 S_Find_Search : aliased constant S := "/SEARCH=*" &
850 S_Find_Source : aliased constant S := "/SOURCE_SEARCH=*" &
853 Find_Switches : aliased constant Switches := (
858 S_Find_Ignore 'Access,
859 S_Find_Object 'Access,
860 S_Find_Print 'Access,
861 S_Find_Project 'Access,
862 S_Project_File 'Access,
863 S_Project_Verb 'Access,
865 S_Find_Search 'Access,
866 S_Find_Source 'Access);
868 ------------------------------
869 -- Switches for GNAT KRUNCH --
870 ------------------------------
872 S_Krunch_Count : aliased constant S := "/COUNT=#" &
875 Krunch_Switches : aliased constant Switches := (1 .. 1 =>
876 S_Krunch_Count 'Access);
878 -------------------------------
879 -- Switches for GNAT LIBRARY --
880 -------------------------------
882 S_Lbr_Config : aliased constant S := "/CONFIG=@" &
885 S_Lbr_Create : aliased constant S := "/CREATE=%" &
888 S_Lbr_Delete : aliased constant S := "/DELETE=%" &
891 S_Lbr_Set : aliased constant S := "/SET=%" &
894 Lbr_Switches : aliased constant Switches := (
895 S_Lbr_Config 'Access,
896 S_Lbr_Create 'Access,
897 S_Lbr_Delete 'Access,
900 ----------------------------
901 -- Switches for GNAT LINK --
902 ----------------------------
904 S_Link_Bind : aliased constant S := "/BIND_FILE=" &
910 S_Link_Debug : aliased constant S := "/DEBUG=" &
920 S_Link_Execut : aliased constant S := "/EXECUTABLE=@" &
923 S_Link_Ident : aliased constant S := "/IDENTIFICATION=" & '"' &
924 "--for-linker=IDENT=" &
927 S_Link_Nocomp : aliased constant S := "/NOCOMPILE " &
930 S_Link_Nofiles : aliased constant S := "/NOSTART_FILES " &
933 S_Link_Noinhib : aliased constant S := "/NOINHIBIT-EXEC " &
934 "--for-linker=--noinhibit-exec";
936 S_Link_Static : aliased constant S := "/STATIC " &
937 "--for-linker=-static";
939 S_Link_Verb : aliased constant S := "/VERBOSE " &
942 S_Link_ZZZZZ : aliased constant S := "/<other> " &
945 Link_Switches : aliased constant Switches := (
947 S_Link_Debug 'Access,
948 S_Link_Execut 'Access,
950 S_Link_Ident 'Access,
951 S_Link_Nocomp 'Access,
952 S_Link_Nofiles 'Access,
953 S_Link_Noinhib 'Access,
954 S_Project_File 'Access,
955 S_Project_Verb 'Access,
956 S_Link_Static 'Access,
958 S_Link_ZZZZZ 'Access);
960 ----------------------------
961 -- Switches for GNAT LIST --
962 ----------------------------
964 S_List_All : aliased constant S := "/ALL_UNITS " &
967 S_List_Current : aliased constant S := "/CURRENT_DIRECTORY " &
970 S_List_Depend : aliased constant S := "/DEPENDENCIES " &
973 S_List_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
976 S_List_Object : aliased constant S := "/OBJECT_SEARCH=*" &
979 S_List_Output : aliased constant S := "/OUTPUT=" &
991 S_List_Search : aliased constant S := "/SEARCH=*" &
994 S_List_Source : aliased constant S := "/SOURCE_SEARCH=*" &
997 List_Switches : aliased constant Switches := (
999 S_List_Current 'Access,
1000 S_List_Depend 'Access,
1002 S_List_Nostinc 'Access,
1003 S_List_Object 'Access,
1004 S_List_Output 'Access,
1005 S_Project_File 'Access,
1006 S_Project_Verb 'Access,
1007 S_List_Search 'Access,
1008 S_List_Source 'Access);
1010 ----------------------------
1011 -- Switches for GNAT MAKE --
1012 ----------------------------
1014 S_Make_All : aliased constant S := "/ALL_FILES " &
1017 S_Make_Bind : aliased constant S := "/BINDER_QUALIFIERS=?" &
1020 S_Make_Comp : aliased constant S := "/COMPILER_QUALIFIERS=?" &
1023 S_Make_Cond : aliased constant S := "/CONDITIONAL_SOURCE_SEARCH=*" &
1026 S_Make_Cont : aliased constant S := "/CONTINUE_ON_ERROR " &
1029 S_Make_Current : aliased constant S := "/CURRENT_DIRECTORY " &
1032 S_Make_Dep : aliased constant S := "/DEPENDENCIES_LIST " &
1035 S_Make_Doobj : aliased constant S := "/DO_OBJECT_CHECK " &
1038 S_Make_Execut : aliased constant S := "/EXECUTABLE=@" &
1041 S_Make_Force : aliased constant S := "/FORCE_COMPILE " &
1044 S_Make_Inplace : aliased constant S := "/IN_PLACE " &
1047 S_Make_Library : aliased constant S := "/LIBRARY_SEARCH=*" &
1050 S_Make_Link : aliased constant S := "/LINKER_QUALIFIERS=?" &
1053 S_Make_Minimal : aliased constant S := "/MINIMAL_RECOMPILATION " &
1056 S_Make_Nolink : aliased constant S := "/NOLINK " &
1059 S_Make_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
1062 S_Make_Nostlib : aliased constant S := "/NOSTD_LIBRARIES " &
1065 S_Make_Object : aliased constant S := "/OBJECT_SEARCH=*" &
1068 S_Make_Proc : aliased constant S := "/PROCESSES=#" &
1071 S_Make_Nojobs : aliased constant S := "/NOPROCESSES " &
1074 S_Make_Quiet : aliased constant S := "/QUIET " &
1077 S_Make_Reason : aliased constant S := "/REASONS " &
1080 S_Make_Search : aliased constant S := "/SEARCH=*" &
1083 S_Make_Skip : aliased constant S := "/SKIP_MISSING=*" &
1086 S_Make_Source : aliased constant S := "/SOURCE_SEARCH=*" &
1089 S_Make_Verbose : aliased constant S := "/VERBOSE " &
1092 Make_Switches : aliased constant Switches := (
1094 S_Make_Bind 'Access,
1095 S_Make_Comp 'Access,
1096 S_Make_Cond 'Access,
1097 S_Make_Cont 'Access,
1098 S_Make_Current 'Access,
1100 S_Make_Doobj 'Access,
1101 S_Make_Execut 'Access,
1103 S_Make_Force 'Access,
1104 S_Make_Inplace 'Access,
1105 S_Make_Library 'Access,
1106 S_Make_Link 'Access,
1107 S_Make_Minimal 'Access,
1108 S_Make_Nolink 'Access,
1109 S_Make_Nostinc 'Access,
1110 S_Make_Nostlib 'Access,
1111 S_Make_Object 'Access,
1112 S_Make_Proc 'Access,
1113 S_Project_File 'Access,
1114 S_Project_Verb 'Access,
1115 S_Make_Nojobs 'Access,
1116 S_Make_Quiet 'Access,
1117 S_Make_Reason 'Access,
1118 S_Make_Search 'Access,
1119 S_Make_Skip 'Access,
1120 S_Make_Source 'Access,
1121 S_Make_Verbose 'Access);
1123 ----------------------------------
1124 -- Switches for GNAT PREPROCESS --
1125 ----------------------------------
1127 S_Prep_Blank : aliased constant S := "/BLANK_LINES " &
1130 S_Prep_Com : aliased constant S := "/COMMENTS " &
1133 S_Prep_Ref : aliased constant S := "/REFERENCE " &
1136 S_Prep_Remove : aliased constant S := "/REMOVE " &
1139 S_Prep_Symbols : aliased constant S := "/SYMBOLS " &
1142 S_Prep_Undef : aliased constant S := "/UNDEFINED " &
1145 S_Prep_Verbose : aliased constant S := "/VERBOSE " &
1148 S_Prep_Version : aliased constant S := "/VERSION " &
1151 Prep_Switches : aliased constant Switches := (
1152 S_Prep_Blank 'Access,
1155 S_Prep_Remove 'Access,
1156 S_Prep_Symbols 'Access,
1157 S_Prep_Undef 'Access,
1158 S_Prep_Verbose 'Access,
1159 S_Prep_Version 'Access);
1161 ------------------------------
1162 -- Switches for GNAT SHARED --
1163 ------------------------------
1165 S_Shared_Debug : aliased constant S := "/DEBUG=" &
1175 S_Shared_Image : aliased constant S := "/IMAGE=@" &
1178 S_Shared_Ident : aliased constant S := "/IDENTIFICATION=" & '"' &
1179 "--for-linker=IDENT=" &
1182 S_Shared_Nofiles : aliased constant S := "/NOSTART_FILES " &
1185 S_Shared_Noinhib : aliased constant S := "/NOINHIBIT-IMAGE " &
1186 "--for-linker=--noinhibit-exec";
1188 S_Shared_Verb : aliased constant S := "/VERBOSE " &
1191 S_Shared_ZZZZZ : aliased constant S := "/<other> " &
1194 Shared_Switches : aliased constant Switches := (
1195 S_Shared_Debug 'Access,
1196 S_Shared_Image 'Access,
1197 S_Shared_Ident 'Access,
1198 S_Shared_Nofiles 'Access,
1199 S_Shared_Noinhib 'Access,
1200 S_Shared_Verb 'Access,
1201 S_Shared_ZZZZZ 'Access);
1203 --------------------------------
1204 -- Switches for GNAT STANDARD --
1205 --------------------------------
1207 Standard_Switches : aliased constant Switches := (1 .. 0 => null);
1209 ----------------------------
1210 -- Switches for GNAT STUB --
1211 ----------------------------
1213 S_Stub_Current : aliased constant S := "/CURRENT_DIRECTORY " &
1216 S_Stub_Full : aliased constant S := "/FULL " &
1219 S_Stub_Header : aliased constant S := "/HEADER=" &
1225 S_Stub_Indent : aliased constant S := "/INDENTATION=#" &
1228 S_Stub_Length : aliased constant S := "/LINE_LENGTH=#" &
1231 S_Stub_Quiet : aliased constant S := "/QUIET " &
1234 S_Stub_Search : aliased constant S := "/SEARCH=*" &
1237 S_Stub_Tree : aliased constant S := "/TREE_FILE=" &
1245 S_Stub_Verbose : aliased constant S := "/VERBOSE " &
1248 Stub_Switches : aliased constant Switches := (
1249 S_Stub_Current 'Access,
1250 S_Stub_Full 'Access,
1251 S_Stub_Header 'Access,
1252 S_Stub_Indent 'Access,
1253 S_Stub_Length 'Access,
1254 S_Stub_Quiet 'Access,
1255 S_Stub_Search 'Access,
1256 S_Stub_Tree 'Access,
1257 S_Stub_Verbose 'Access);
1259 ------------------------------
1260 -- Switches for GNAT SYSTEM --
1261 ------------------------------
1263 System_Switches : aliased constant Switches := (1 .. 0 => null);
1265 ----------------------------
1266 -- Switches for GNAT XREF --
1267 ----------------------------
1269 S_Xref_All : aliased constant S := "/ALL_FILES " &
1272 S_Xref_Full : aliased constant S := "/FULL_PATHNAME " &
1275 S_Xref_Global : aliased constant S := "/IGNORE_LOCALS " &
1278 S_Xref_Object : aliased constant S := "/OBJECT_SEARCH=*" &
1281 S_Xref_Project : aliased constant S := "/PROJECT=@" &
1284 S_Xref_Search : aliased constant S := "/SEARCH=*" &
1287 S_Xref_Source : aliased constant S := "/SOURCE_SEARCH=*" &
1290 S_Xref_Output : aliased constant S := "/UNUSED " &
1293 Xref_Switches : aliased constant Switches := (
1296 S_Xref_Full 'Access,
1297 S_Xref_Global 'Access,
1298 S_Xref_Object 'Access,
1299 S_Xref_Project 'Access,
1300 S_Project_File 'Access,
1301 S_Project_Verb 'Access,
1302 S_Xref_Search 'Access,
1303 S_Xref_Source 'Access,
1304 S_Xref_Output 'Access);
1310 -- The command table contains an entry for each command recognized by
1311 -- GNATCmd. The entries are represented by an array of records.
1313 type Parameter_Type is
1314 -- A parameter is defined as a whitespace bounded string, not begining
1315 -- with a slash. (But see note under FILES_OR_WILDCARD).
1317 -- A required file or directory parameter.
1320 -- An optional file or directory parameter.
1323 -- A parameter that's passed through as is (not canonicalized)
1326 -- An unlimited number of writespace separate file or directory
1327 -- parameters including wildcard specifications.
1330 -- A comma separated list of files and/or wildcard file specifications.
1331 -- A comma preceded by or followed by whitespace is considered as a
1332 -- single comma character w/o whitespace.
1334 type Parameter_Array is array (Natural range <>) of Parameter_Type;
1335 type Parameter_Ref is access all Parameter_Array;
1337 type Command_Entry is record
1339 -- Command name for GNAT xxx command
1342 -- A usage string, used for error messages
1344 Unixcmd : String_Ptr;
1345 -- Corresponding Unix command
1347 Switches : Switches_Ptr;
1348 -- Pointer to array of switch strings
1350 Params : Parameter_Ref;
1351 -- Describes the allowable types of parameters.
1352 -- Params (1) is the type of the first parameter, etc.
1353 -- An empty parameter array means this command takes no parameters.
1355 Defext : String (1 .. 3);
1356 -- Default extension. If non-blank, then this extension is supplied by
1357 -- default as the extension for any file parameter which does not have
1358 -- an extension already.
1361 -------------------------
1362 -- INTERNAL STRUCTURES --
1363 -------------------------
1365 -- The switches and commands are defined by strings in the previous
1366 -- section so that they are easy to modify, but internally, they are
1367 -- kept in a more conveniently accessible form described in this
1370 -- Commands, command qualifers and options have a similar common format
1371 -- so that searching for matching names can be done in a common manner.
1373 type Item_Id is (Id_Command, Id_Switch, Id_Option);
1375 type Translation_Type is
1378 -- A qualifier with no options.
1379 -- Example: GNAT MAKE /VERBOSE
1382 -- A qualifier followed by a list of directories
1383 -- Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
1386 -- A qualifier followed by one directory
1387 -- Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
1390 -- A quailifier followed by a filename
1391 -- Example: GNAT LINK /EXECUTABLE=FOO.EXE
1394 -- A qualifier followed by a numeric value.
1395 -- Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
1398 -- A qualifier followed by a quoted string. Only used by
1399 -- /IDENTIFICATION qualfier.
1400 -- Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
1403 -- A qualifier followed by a list of options.
1404 -- Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
1407 -- A qualifier followed by a list. Only used for
1408 -- MAKE /COMPILER_QUALIFIERS /BINDER_QUALIFIERS /LINKER_QUALIFIERS
1409 -- (gnatmake -cargs -bargs -largs )
1410 -- Example: GNAT MAKE ... /LINKER_QUALIFIERS /VERBOSE FOOBAR.OBJ
1413 -- A qualifier passed directly to the linker. Only used
1414 -- for LINK and SHARED if no other match is found.
1415 -- Example: GNAT LINK FOO.ALI /SYSSHR
1418 -- A qualifier followed by a legal linker symbol prefix. Only used
1419 -- for BIND /BUILD_LIBRARY (gnatbind -Lxyz).
1420 -- Example: GNAT BIND /BUILD_LIBRARY=foobar
1423 type Item (Id : Item_Id);
1424 type Item_Ptr is access all Item;
1426 type Item (Id : Item_Id) is record
1428 -- Name of the command, switch (with slash) or option
1431 -- Pointer to next item on list, always has the same Id value
1433 Unix_String : String_Ptr;
1434 -- Corresponding Unix string. For a command, this is the unix command
1435 -- name and possible default switches. For a switch or option it is
1436 -- the unix switch string.
1442 Switches : Item_Ptr;
1443 -- Pointer to list of switch items for the command, linked
1444 -- through the Next fields with null terminating the list.
1447 -- Usage information, used only for errors and the default
1448 -- list of commands output.
1450 Params : Parameter_Ref;
1451 -- Array of parameters
1453 Defext : String (1 .. 3);
1454 -- Default extension. If non-blank, then this extension is
1455 -- supplied by default as the extension for any file parameter
1456 -- which does not have an extension already.
1460 Translation : Translation_Type;
1461 -- Type of switch translation. For all cases, except Options,
1462 -- this is the only field needed, since the Unix translation
1463 -- is found in Unix_String.
1466 -- For the Options case, this field is set to point to a list
1467 -- of options item (for this case Unix_String is null in the
1468 -- main switch item). The end of the list is marked by null.
1473 -- No special fields needed, since Name and Unix_String are
1474 -- sufficient to completely described an option.
1479 subtype Command_Item is Item (Id_Command);
1480 subtype Switch_Item is Item (Id_Switch);
1481 subtype Option_Item is Item (Id_Option);
1483 ----------------------------------
1484 -- Declarations for GNATCMD use --
1485 ----------------------------------
1487 Commands : Item_Ptr;
1488 -- Pointer to head of list of command items, one for each command, with
1489 -- the end of the list marked by a null pointer.
1491 Last_Command : Item_Ptr;
1492 -- Pointer to last item in Commands list
1494 Normal_Exit : exception;
1495 -- Raise this exception for normal program termination
1497 Error_Exit : exception;
1498 -- Raise this exception if error detected
1500 Errors : Natural := 0;
1501 -- Count errors detected
1504 -- Pointer to command item for current command
1506 Make_Commands_Active : Item_Ptr := null;
1507 -- Set to point to Command entry for COMPILE, BIND, or LINK as appropriate
1508 -- if a COMMANDS_TRANSLATION switch has been encountered while processing
1511 My_Exit_Status : Exit_Status := Success;
1513 package Buffer is new Table.Table (
1514 Table_Component_Type => Character,
1515 Table_Index_Type => Integer,
1516 Table_Low_Bound => 1,
1517 Table_Initial => 4096,
1518 Table_Increment => 2,
1519 Table_Name => "Buffer");
1521 Param_Count : Natural := 0;
1522 -- Number of parameter arguments so far
1527 Display_Command : Boolean := False;
1528 -- Set true if /? switch causes display of generated command
1530 -----------------------
1531 -- Local Subprograms --
1532 -----------------------
1534 function Init_Object_Dirs return String_Ptr;
1536 function Invert_Sense (S : String) return String_Ptr;
1537 -- Given a unix switch string S, computes the inverse (adding or
1538 -- removing ! characters as required), and returns a pointer to
1539 -- the allocated result on the heap.
1541 function Is_Extensionless (F : String) return Boolean;
1542 -- Returns true if the filename has no extension.
1544 function Match (S1, S2 : String) return Boolean;
1545 -- Determines whether S1 and S2 match. This is a case insensitive match.
1547 function Match_Prefix (S1, S2 : String) return Boolean;
1548 -- Determines whether S1 matches a prefix of S2. This is also a case
1549 -- insensitive match (for example Match ("AB","abc") is True).
1551 function Matching_Name
1554 Quiet : Boolean := False)
1556 -- Determines if the item list headed by Itm and threaded through the
1557 -- Next fields (with null marking the end of the list), contains an
1558 -- entry that uniquely matches the given string. The match is case
1559 -- insensitive and permits unique abbreviation. If the match succeeds,
1560 -- then a pointer to the matching item is returned. Otherwise, an
1561 -- appropriate error message is written. Note that the discriminant
1562 -- of Itm is used to determine the appropriate form of this message.
1563 -- Quiet is normally False as shown, if it is set to True, then no
1564 -- error message is generated in a not found situation (null is still
1565 -- returned to indicate the not-found situation).
1567 function OK_Alphanumerplus (S : String) return Boolean;
1568 -- Checks that S is a string of alphanumeric characters,
1569 -- returning True if all alphanumeric characters,
1570 -- False if empty or a non-alphanumeric character is present.
1572 function OK_Integer (S : String) return Boolean;
1573 -- Checks that S is a string of digits, returning True if all digits,
1574 -- False if empty or a non-digit is present.
1576 procedure Place (C : Character);
1577 -- Place a single character in the buffer, updating Ptr
1579 procedure Place (S : String);
1580 -- Place a string character in the buffer, updating Ptr
1582 procedure Place_Lower (S : String);
1583 -- Place string in buffer, forcing letters to lower case, updating Ptr
1585 procedure Place_Unix_Switches (S : String_Ptr);
1586 -- Given a unix switch string, place corresponding switches in Buffer,
1587 -- updating Ptr appropriatelly. Note that in the case of use of ! the
1588 -- result may be to remove a previously placed switch.
1590 procedure Validate_Command_Or_Option (N : String_Ptr);
1591 -- Check that N is a valid command or option name, i.e. that it is of the
1592 -- form of an Ada identifier with upper case letters and underscores.
1594 procedure Validate_Unix_Switch (S : String_Ptr);
1595 -- Check that S is a valid switch string as described in the syntax for
1596 -- the switch table item UNIX_SWITCH or else begins with a backquote.
1598 ----------------------
1599 -- Init_Object_Dirs --
1600 ----------------------
1602 function Init_Object_Dirs return String_Ptr is
1603 Object_Dirs : Integer;
1604 Object_Dir : array (Integer range 1 .. 256) of String_Access;
1605 Object_Dir_Name : String_Access;
1609 Object_Dir_Name := String_Access (Object_Dir_Default_Name);
1610 Get_Next_Dir_In_Path_Init (Object_Dir_Name);
1614 Dir : String_Access := String_Access
1615 (Get_Next_Dir_In_Path (Object_Dir_Name));
1617 exit when Dir = null;
1618 Object_Dirs := Object_Dirs + 1;
1619 Object_Dir (Object_Dirs)
1620 := String_Access (Normalize_Directory_Name (Dir.all));
1624 for Dirs in 1 .. Object_Dirs loop
1625 Buffer.Increment_Last;
1626 Buffer.Table (Buffer.Last) := '-';
1627 Buffer.Increment_Last;
1628 Buffer.Table (Buffer.Last) := 'L';
1629 Object_Dir_Name := new String'(
1630 To_Canonical_Dir_Spec
1631 (To_Host_Dir_Spec (Object_Dir (Dirs).all, True).all, True).all);
1633 for J in Object_Dir_Name'Range loop
1634 Buffer.Increment_Last;
1635 Buffer.Table (Buffer.Last) := Object_Dir_Name (J);
1638 Buffer.Increment_Last;
1639 Buffer.Table (Buffer.Last) := ' ';
1642 Buffer.Increment_Last;
1643 Buffer.Table (Buffer.Last) := '-';
1644 Buffer.Increment_Last;
1645 Buffer.Table (Buffer.Last) := 'l';
1646 Buffer.Increment_Last;
1647 Buffer.Table (Buffer.Last) := 'g';
1648 Buffer.Increment_Last;
1649 Buffer.Table (Buffer.Last) := 'n';
1650 Buffer.Increment_Last;
1651 Buffer.Table (Buffer.Last) := 'a';
1652 Buffer.Increment_Last;
1653 Buffer.Table (Buffer.Last) := 't';
1655 if Hostparm.OpenVMS then
1656 Buffer.Increment_Last;
1657 Buffer.Table (Buffer.Last) := ' ';
1658 Buffer.Increment_Last;
1659 Buffer.Table (Buffer.Last) := '-';
1660 Buffer.Increment_Last;
1661 Buffer.Table (Buffer.Last) := 'l';
1662 Buffer.Increment_Last;
1663 Buffer.Table (Buffer.Last) := 'd';
1664 Buffer.Increment_Last;
1665 Buffer.Table (Buffer.Last) := 'e';
1666 Buffer.Increment_Last;
1667 Buffer.Table (Buffer.Last) := 'c';
1668 Buffer.Increment_Last;
1669 Buffer.Table (Buffer.Last) := 'g';
1670 Buffer.Increment_Last;
1671 Buffer.Table (Buffer.Last) := 'n';
1672 Buffer.Increment_Last;
1673 Buffer.Table (Buffer.Last) := 'a';
1674 Buffer.Increment_Last;
1675 Buffer.Table (Buffer.Last) := 't';
1678 return new String'(String (Buffer.Table (1 .. Buffer.Last)));
1679 end Init_Object_Dirs;
1685 function Invert_Sense (S : String) return String_Ptr is
1686 Sinv : String (1 .. S'Length * 2);
1687 -- Result (for sure long enough)
1689 Sinvp : Natural := 0;
1690 -- Pointer to output string
1693 for Sp in S'Range loop
1694 if Sp = S'First or else S (Sp - 1) = ',' then
1695 if S (Sp) = '!' then
1698 Sinv (Sinvp + 1) := '!';
1699 Sinv (Sinvp + 2) := S (Sp);
1704 Sinv (Sinvp + 1) := S (Sp);
1709 return new String'(Sinv (1 .. Sinvp));
1712 ----------------------
1713 -- Is_Extensionless --
1714 ----------------------
1716 function Is_Extensionless (F : String) return Boolean is
1718 for J in reverse F'Range loop
1721 elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
1727 end Is_Extensionless;
1733 function Match (S1, S2 : String) return Boolean is
1734 Dif : constant Integer := S2'First - S1'First;
1738 if S1'Length /= S2'Length then
1742 for J in S1'Range loop
1743 if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
1756 function Match_Prefix (S1, S2 : String) return Boolean is
1758 if S1'Length > S2'Length then
1761 return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
1769 function Matching_Name
1772 Quiet : Boolean := False)
1778 -- Little procedure to output command/qualifier/option as appropriate
1779 -- and bump error count.
1787 Errors := Errors + 1;
1792 Put (Standard_Error, "command");
1796 Put (Standard_Error, "qualifier");
1798 Put (Standard_Error, "switch");
1802 Put (Standard_Error, "option");
1806 Put (Standard_Error, "input");
1810 Put (Standard_Error, ": ");
1811 Put (Standard_Error, S);
1815 -- Start of processing for Matching_Name
1818 -- If exact match, that's the one we want
1821 while P1 /= null loop
1822 if Match (S, P1.Name.all) then
1829 -- Now check for prefix matches
1832 while P1 /= null loop
1833 if P1.Name.all = "/<other>" then
1836 elsif not Match_Prefix (S, P1.Name.all) then
1840 -- Here we have found one matching prefix, so see if there is
1841 -- another one (which is an ambiguity)
1844 while P2 /= null loop
1845 if Match_Prefix (S, P2.Name.all) then
1847 Put (Standard_Error, "ambiguous ");
1849 Put (Standard_Error, " (matches ");
1850 Put (Standard_Error, P1.Name.all);
1852 while P2 /= null loop
1853 if Match_Prefix (S, P2.Name.all) then
1854 Put (Standard_Error, ',');
1855 Put (Standard_Error, P2.Name.all);
1861 Put_Line (Standard_Error, ")");
1870 -- If we fall through that loop, then there was only one match
1876 -- If we fall through outer loop, there was no match
1879 Put (Standard_Error, "unrecognized ");
1881 New_Line (Standard_Error);
1887 -----------------------
1888 -- OK_Alphanumerplus --
1889 -----------------------
1891 function OK_Alphanumerplus (S : String) return Boolean is
1893 if S'Length = 0 then
1897 for J in S'Range loop
1898 if not (Is_Alphanumeric (S (J)) or else
1899 S (J) = '_' or else S (J) = '$')
1907 end OK_Alphanumerplus;
1913 function OK_Integer (S : String) return Boolean is
1915 if S'Length = 0 then
1919 for J in S'Range loop
1920 if not Is_Digit (S (J)) then
1933 procedure Place (C : Character) is
1935 Buffer.Increment_Last;
1936 Buffer.Table (Buffer.Last) := C;
1939 procedure Place (S : String) is
1941 for J in S'Range loop
1950 procedure Place_Lower (S : String) is
1952 for J in S'Range loop
1953 Place (To_Lower (S (J)));
1957 -------------------------
1958 -- Place_Unix_Switches --
1959 -------------------------
1961 procedure Place_Unix_Switches (S : String_Ptr) is
1962 P1, P2, P3 : Natural;
1968 while P1 <= S'Last loop
1969 if S (P1) = '!' then
1977 pragma Assert (S (P1) = '-' or else S (P1) = '`');
1979 while P2 < S'Last and then S (P2 + 1) /= ',' loop
1983 -- Switch is now in S (P1 .. P2)
1985 Slen := P2 - P1 + 1;
1989 while P3 <= Buffer.Last - Slen loop
1990 if Buffer.Table (P3) = ' '
1991 and then String (Buffer.Table (P3 + 1 .. P3 + Slen))
1993 and then (P3 + Slen = Buffer.Last
1995 Buffer.Table (P3 + Slen + 1) = ' ')
1997 Buffer.Table (P3 .. Buffer.Last - Slen - 1) :=
1998 Buffer.Table (P3 + Slen + 1 .. Buffer.Last);
1999 Buffer.Set_Last (Buffer.Last - Slen - 1);
2009 if S (P1) = '`' then
2013 Place (S (P1 .. P2));
2018 end Place_Unix_Switches;
2020 --------------------------------
2021 -- Validate_Command_Or_Option --
2022 --------------------------------
2024 procedure Validate_Command_Or_Option (N : String_Ptr) is
2026 pragma Assert (N'Length > 0);
2028 for J in N'Range loop
2030 pragma Assert (N (J - 1) /= '_');
2033 pragma Assert (Is_Upper (N (J)) or else Is_Digit (N (J)));
2037 end Validate_Command_Or_Option;
2039 --------------------------
2040 -- Validate_Unix_Switch --
2041 --------------------------
2043 procedure Validate_Unix_Switch (S : String_Ptr) is
2045 if S (S'First) = '`' then
2049 pragma Assert (S (S'First) = '-' or else S (S'First) = '!');
2051 for J in S'First + 1 .. S'Last loop
2052 pragma Assert (S (J) /= ' ');
2055 pragma Assert (S (J - 1) = ',' and then S (J + 1) = '-');
2059 end Validate_Unix_Switch;
2061 ----------------------
2062 -- List of Commands --
2063 ----------------------
2065 -- Note that we put this after all the local bodies to avoid
2066 -- some access before elaboration problems.
2068 Command_List : array (Natural range <>) of Command_Entry := (
2070 (Cname => new S'("BIND"),
2071 Usage => new S'("GNAT BIND file[.ali] /qualifiers"),
2072 Unixcmd => new S'("gnatbind"),
2073 Switches => Bind_Switches'Access,
2074 Params => new Parameter_Array'(1 => File),
2077 (Cname => new S'("CHOP"),
2078 Usage => new S'("GNAT CHOP file [directory] /qualifiers"),
2079 Unixcmd => new S'("gnatchop"),
2080 Switches => Chop_Switches'Access,
2081 Params => new Parameter_Array'(1 => File, 2 => Optional_File),
2084 (Cname => new S'("COMPILE"),
2085 Usage => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
2086 Unixcmd => new S'("gcc -c -x ada"),
2087 Switches => GCC_Switches'Access,
2088 Params => new Parameter_Array'(1 => Files_Or_Wildcard),
2091 (Cname => new S'("ELIM"),
2092 Usage => new S'("GNAT ELIM name /qualifiers"),
2093 Unixcmd => new S'("gnatelim"),
2094 Switches => Elim_Switches'Access,
2095 Params => new Parameter_Array'(1 => Other_As_Is),
2098 (Cname => new S'("FIND"),
2099 Usage => new S'("GNAT FIND pattern[:sourcefile[:line[:column]]]" &
2100 " filespec[,...] /qualifiers"),
2101 Unixcmd => new S'("gnatfind"),
2102 Switches => Find_Switches'Access,
2103 Params => new Parameter_Array'(1 => Other_As_Is,
2104 2 => Files_Or_Wildcard),
2107 (Cname => new S'("KRUNCH"),
2108 Usage => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
2109 Unixcmd => new S'("gnatkr"),
2110 Switches => Krunch_Switches'Access,
2111 Params => new Parameter_Array'(1 => File),
2114 (Cname => new S'("LIBRARY"),
2115 Usage => new S'("GNAT LIBRARY /[CREATE | SET | DELETE]=directory"
2116 & " [/CONFIG=file]"),
2117 Unixcmd => new S'("gnatlbr"),
2118 Switches => Lbr_Switches'Access,
2119 Params => new Parameter_Array'(1 .. 0 => File),
2122 (Cname => new S'("LINK"),
2123 Usage => new S'("GNAT LINK file[.ali]"
2124 & " [extra obj_&_lib_&_exe_&_opt files]"
2126 Unixcmd => new S'("gnatlink"),
2127 Switches => Link_Switches'Access,
2128 Params => new Parameter_Array'(1 => Unlimited_Files),
2131 (Cname => new S'("LIST"),
2132 Usage => new S'("GNAT LIST /qualifiers object_or_ali_file"),
2133 Unixcmd => new S'("gnatls"),
2134 Switches => List_Switches'Access,
2135 Params => new Parameter_Array'(1 => File),
2138 (Cname => new S'("MAKE"),
2140 new S'("GNAT MAKE file /qualifiers (includes COMPILE /qualifiers)"),
2141 Unixcmd => new S'("gnatmake"),
2142 Switches => Make_Switches'Access,
2143 Params => new Parameter_Array'(1 => File),
2146 (Cname => new S'("PREPROCESS"),
2147 Usage => new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
2148 Unixcmd => new S'("gnatprep"),
2149 Switches => Prep_Switches'Access,
2150 Params => new Parameter_Array'(1 .. 3 => File),
2153 (Cname => new S'("SHARED"),
2154 Usage => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt files]"
2156 Unixcmd => new S'("gcc -shared " & Init_Object_Dirs.all),
2157 Switches => Shared_Switches'Access,
2158 Params => new Parameter_Array'(1 => Unlimited_Files),
2161 (Cname => new S'("STANDARD"),
2162 Usage => new S'("GNAT STANDARD"),
2163 Unixcmd => new S'("gnatpsta"),
2164 Switches => Standard_Switches'Access,
2165 Params => new Parameter_Array'(1 .. 0 => File),
2168 (Cname => new S'("STUB"),
2169 Usage => new S'("GNAT STUB file [directory] /qualifiers"),
2170 Unixcmd => new S'("gnatstub"),
2171 Switches => Stub_Switches'Access,
2172 Params => new Parameter_Array'(1 => File, 2 => Optional_File),
2175 (Cname => new S'("SYSTEM"),
2176 Usage => new S'("GNAT SYSTEM"),
2177 Unixcmd => new S'("gnatpsys"),
2178 Switches => System_Switches'Access,
2179 Params => new Parameter_Array'(1 .. 0 => File),
2182 (Cname => new S'("XREF"),
2183 Usage => new S'("GNAT XREF filespec[,...] /qualifiers"),
2184 Unixcmd => new S'("gnatxref"),
2185 Switches => Xref_Switches'Access,
2186 Params => new Parameter_Array'(1 => Files_Or_Wildcard),
2190 -------------------------------------
2191 -- Start of processing for GNATCmd --
2192 -------------------------------------
2197 -- First we must preprocess the string form of the command and options
2198 -- list into the internal form that we use.
2200 for C in Command_List'Range loop
2203 Command : Item_Ptr := new Command_Item;
2205 Last_Switch : Item_Ptr;
2206 -- Last switch in list
2209 -- Link new command item into list of commands
2211 if Last_Command = null then
2212 Commands := Command;
2214 Last_Command.Next := Command;
2217 Last_Command := Command;
2219 -- Fill in fields of new command item
2221 Command.Name := Command_List (C).Cname;
2222 Command.Usage := Command_List (C).Usage;
2223 Command.Unix_String := Command_List (C).Unixcmd;
2224 Command.Params := Command_List (C).Params;
2225 Command.Defext := Command_List (C).Defext;
2227 Validate_Command_Or_Option (Command.Name);
2229 -- Process the switch list
2231 for S in Command_List (C).Switches'Range loop
2233 SS : constant String_Ptr := Command_List (C).Switches (S);
2235 P : Natural := SS'First;
2236 Sw : Item_Ptr := new Switch_Item;
2238 Last_Opt : Item_Ptr;
2239 -- Pointer to last option
2242 -- Link new switch item into list of switches
2244 if Last_Switch = null then
2245 Command.Switches := Sw;
2247 Last_Switch.Next := Sw;
2252 -- Process switch string, first get name
2254 while SS (P) /= ' ' and SS (P) /= '=' loop
2258 Sw.Name := new String'(SS (SS'First .. P - 1));
2260 -- Direct translation case
2262 if SS (P) = ' ' then
2263 Sw.Translation := T_Direct;
2264 Sw.Unix_String := new String'(SS (P + 1 .. SS'Last));
2265 Validate_Unix_Switch (Sw.Unix_String);
2267 if SS (P - 1) = '>' then
2268 Sw.Translation := T_Other;
2270 elsif SS (P + 1) = '`' then
2273 -- Create the inverted case (/NO ..)
2275 elsif SS (SS'First + 1 .. SS'First + 2) /= "NO" then
2276 Sw := new Switch_Item;
2277 Last_Switch.Next := Sw;
2281 new String'("/NO" & SS (SS'First + 1 .. P - 1));
2282 Sw.Translation := T_Direct;
2283 Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
2284 Validate_Unix_Switch (Sw.Unix_String);
2287 -- Directories translation case
2289 elsif SS (P + 1) = '*' then
2290 pragma Assert (SS (SS'Last) = '*');
2291 Sw.Translation := T_Directories;
2292 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2293 Validate_Unix_Switch (Sw.Unix_String);
2295 -- Directory translation case
2297 elsif SS (P + 1) = '%' then
2298 pragma Assert (SS (SS'Last) = '%');
2299 Sw.Translation := T_Directory;
2300 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2301 Validate_Unix_Switch (Sw.Unix_String);
2303 -- File translation case
2305 elsif SS (P + 1) = '@' then
2306 pragma Assert (SS (SS'Last) = '@');
2307 Sw.Translation := T_File;
2308 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2309 Validate_Unix_Switch (Sw.Unix_String);
2311 -- Numeric translation case
2313 elsif SS (P + 1) = '#' then
2314 pragma Assert (SS (SS'Last) = '#');
2315 Sw.Translation := T_Numeric;
2316 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2317 Validate_Unix_Switch (Sw.Unix_String);
2319 -- Alphanumerplus translation case
2321 elsif SS (P + 1) = '|' then
2322 pragma Assert (SS (SS'Last) = '|');
2323 Sw.Translation := T_Alphanumplus;
2324 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2325 Validate_Unix_Switch (Sw.Unix_String);
2327 -- String translation case
2329 elsif SS (P + 1) = '"' then
2330 pragma Assert (SS (SS'Last) = '"');
2331 Sw.Translation := T_String;
2332 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2333 Validate_Unix_Switch (Sw.Unix_String);
2335 -- Commands translation case
2337 elsif SS (P + 1) = '?' then
2338 Sw.Translation := T_Commands;
2339 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last));
2341 -- Options translation case
2344 Sw.Translation := T_Options;
2345 Sw.Unix_String := new String'("");
2347 P := P + 1; -- bump past =
2348 while P <= SS'Last loop
2350 Opt : Item_Ptr := new Option_Item;
2354 -- Link new option item into options list
2356 if Last_Opt = null then
2359 Last_Opt.Next := Opt;
2364 -- Fill in fields of new option item
2367 while SS (Q) /= ' ' loop
2371 Opt.Name := new String'(SS (P .. Q - 1));
2372 Validate_Command_Or_Option (Opt.Name);
2377 while Q <= SS'Last and then SS (Q) /= ' ' loop
2381 Opt.Unix_String := new String'(SS (P .. Q - 1));
2382 Validate_Unix_Switch (Opt.Unix_String);
2392 -- If no parameters, give complete list of commands
2394 if Argument_Count = 0 then
2395 Put_Line ("List of available commands");
2398 while Commands /= null loop
2399 Put (Commands.Usage.all);
2401 Put_Line (Commands.Unix_String.all);
2402 Commands := Commands.Next;
2411 exit when Arg_Num > Argument_Count;
2414 Argv : String_Access;
2417 function Get_Arg_End
2421 -- Begins looking at Arg_Idx + 1 and returns the index of the
2422 -- last character before a slash or else the index of the last
2423 -- character in the string Argv.
2425 function Get_Arg_End
2431 for J in Arg_Idx + 1 .. Argv'Last loop
2432 if Argv (J) = '/' then
2441 Argv := new String'(Argument (Arg_Num));
2442 Arg_Idx := Argv'First;
2444 <<Tryagain_After_Coalesce>>
2447 Next_Arg_Idx : Integer;
2448 Arg : String_Access;
2451 Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
2452 Arg := new String'(Argv (Arg_Idx .. Next_Arg_Idx));
2454 -- The first one must be a command name
2456 if Arg_Num = 1 and then Arg_Idx = Argv'First then
2458 Command := Matching_Name (Arg.all, Commands);
2460 if Command = null then
2464 -- Give usage information if only command given
2466 if Argument_Count = 1 and then Next_Arg_Idx = Argv'Last
2468 not (Command.Name.all = "SYSTEM"
2469 or else Command.Name.all = "STANDARD")
2471 Put_Line ("List of available qualifiers and options");
2474 Put (Command.Usage.all);
2476 Put_Line (Command.Unix_String.all);
2479 Sw : Item_Ptr := Command.Switches;
2482 while Sw /= null loop
2486 case Sw.Translation is
2490 Put_Line (Sw.Unix_String.all & "/<other>");
2494 Put_Line (Sw.Unix_String.all);
2496 when T_Directories =>
2497 Put ("=(direc,direc,..direc)");
2499 Put (Sw.Unix_String.all);
2501 Put (Sw.Unix_String.all);
2502 Put_Line (" direc ...");
2507 Put (Sw.Unix_String.all);
2509 if Sw.Unix_String (Sw.Unix_String'Last)
2515 Put_Line ("directory ");
2520 Put (Sw.Unix_String.all);
2522 if Sw.Unix_String (Sw.Unix_String'Last)
2534 if Sw.Unix_String (Sw.Unix_String'First)
2538 (Sw.Unix_String'First + 1
2539 .. Sw.Unix_String'Last));
2541 Put (Sw.Unix_String.all);
2546 when T_Alphanumplus =>
2550 if Sw.Unix_String (Sw.Unix_String'First)
2554 (Sw.Unix_String'First + 1
2555 .. Sw.Unix_String'Last));
2557 Put (Sw.Unix_String.all);
2569 Put (Sw.Unix_String.all);
2571 if Sw.Unix_String (Sw.Unix_String'Last)
2581 Put (" (switches for ");
2582 Put (Sw.Unix_String (
2583 Sw.Unix_String'First + 7
2584 .. Sw.Unix_String'Last));
2587 Put (Sw.Unix_String (
2588 Sw.Unix_String'First
2589 .. Sw.Unix_String'First + 5));
2590 Put_Line (" switches");
2594 Opt : Item_Ptr := Sw.Options;
2597 Put_Line ("=(option,option..)");
2599 while Opt /= null loop
2603 if Opt = Sw.Options then
2608 Put_Line (Opt.Unix_String.all);
2622 Place (Command.Unix_String.all);
2624 -- Special handling for internal debugging switch /?
2626 elsif Arg.all = "/?" then
2627 Display_Command := True;
2629 -- Copy -switch unchanged
2631 elsif Arg (Arg'First) = '-' then
2635 -- Copy quoted switch with quotes stripped
2637 elsif Arg (Arg'First) = '"' then
2638 if Arg (Arg'Last) /= '"' then
2639 Put (Standard_Error, "misquoted argument: ");
2640 Put_Line (Standard_Error, Arg.all);
2641 Errors := Errors + 1;
2644 Put (Arg (Arg'First + 1 .. Arg'Last - 1));
2647 -- Parameter Argument
2649 elsif Arg (Arg'First) /= '/'
2650 and then Make_Commands_Active = null
2652 Param_Count := Param_Count + 1;
2654 if Param_Count <= Command.Params'Length then
2656 case Command.Params (Param_Count) is
2658 when File | Optional_File =>
2660 Normal_File : String_Access
2661 := To_Canonical_File_Spec (Arg.all);
2664 Place_Lower (Normal_File.all);
2666 if Is_Extensionless (Normal_File.all)
2667 and then Command.Defext /= " "
2670 Place (Command.Defext);
2674 when Unlimited_Files =>
2676 Normal_File : String_Access
2677 := To_Canonical_File_Spec (Arg.all);
2679 File_Is_Wild : Boolean := False;
2680 File_List : String_Access_List_Access;
2682 for I in Arg'Range loop
2684 or else Arg (I) = '%'
2686 File_Is_Wild := True;
2690 if File_Is_Wild then
2691 File_List := To_Canonical_File_List
2694 for I in File_List.all'Range loop
2696 Place_Lower (File_List.all (I).all);
2700 Place_Lower (Normal_File.all);
2702 if Is_Extensionless (Normal_File.all)
2703 and then Command.Defext /= " "
2706 Place (Command.Defext);
2710 Param_Count := Param_Count - 1;
2717 when Files_Or_Wildcard =>
2719 -- Remove spaces from a comma separated list
2720 -- of file names and adjust control variables
2723 while Arg_Num < Argument_Count and then
2724 (Argv (Argv'Last) = ',' xor
2725 Argument (Arg_Num + 1)
2726 (Argument (Arg_Num + 1)'First) = ',')
2728 Argv := new String'(Argv.all
2729 & Argument (Arg_Num + 1));
2730 Arg_Num := Arg_Num + 1;
2731 Arg_Idx := Argv'First;
2732 Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
2734 new String'(Argv (Arg_Idx .. Next_Arg_Idx));
2737 -- Parse the comma separated list of VMS filenames
2738 -- and place them on the command line as space
2739 -- separated Unix style filenames. Lower case and
2740 -- add default extension as appropriate.
2743 Arg1_Idx : Integer := Arg'First;
2745 function Get_Arg1_End
2746 (Arg : String; Arg_Idx : Integer)
2748 -- Begins looking at Arg_Idx + 1 and
2749 -- returns the index of the last character
2750 -- before a comma or else the index of the
2751 -- last character in the string Arg.
2753 function Get_Arg1_End
2754 (Arg : String; Arg_Idx : Integer)
2758 for I in Arg_Idx + 1 .. Arg'Last loop
2759 if Arg (I) = ',' then
2770 Next_Arg1_Idx : Integer
2771 := Get_Arg1_End (Arg.all, Arg1_Idx);
2774 := Arg (Arg1_Idx .. Next_Arg1_Idx);
2776 Normal_File : String_Access
2777 := To_Canonical_File_Spec (Arg1);
2781 Place_Lower (Normal_File.all);
2783 if Is_Extensionless (Normal_File.all)
2784 and then Command.Defext /= " "
2787 Place (Command.Defext);
2790 Arg1_Idx := Next_Arg1_Idx + 1;
2793 exit when Arg1_Idx > Arg'Last;
2795 -- Don't allow two or more commas in a row
2797 if Arg (Arg1_Idx) = ',' then
2798 Arg1_Idx := Arg1_Idx + 1;
2799 if Arg1_Idx > Arg'Last or else
2800 Arg (Arg1_Idx) = ','
2802 Put_Line (Standard_Error,
2803 "Malformed Parameter: " & Arg.all);
2804 Put (Standard_Error, "usage: ");
2805 Put_Line (Standard_Error,
2816 -- Qualifier argument
2823 Endp : Natural := 0; -- avoid warning!
2828 while SwP < Arg'Last and then Arg (SwP + 1) /= '=' loop
2832 -- At this point, the switch name is in
2833 -- Arg (Arg'First..SwP) and if that is not the whole
2834 -- switch, then there is an equal sign at
2835 -- Arg (SwP + 1) and the rest of Arg is what comes
2836 -- after the equal sign.
2838 -- If make commands are active, see if we have another
2839 -- COMMANDS_TRANSLATION switch belonging to gnatmake.
2841 if Make_Commands_Active /= null then
2844 (Arg (Arg'First .. SwP),
2848 if Sw /= null and then Sw.Translation = T_Commands then
2854 (Arg (Arg'First .. SwP),
2855 Make_Commands_Active.Switches,
2859 -- For case of GNAT MAKE or CHOP, if we cannot find the
2860 -- switch, then see if it is a recognized compiler switch
2861 -- instead, and if so process the compiler switch.
2863 elsif Command.Name.all = "MAKE"
2864 or else Command.Name.all = "CHOP" then
2867 (Arg (Arg'First .. SwP),
2874 (Arg (Arg'First .. SwP),
2875 Matching_Name ("COMPILE", Commands).Switches,
2879 -- For all other cases, just search the relevant command
2884 (Arg (Arg'First .. SwP),
2890 case Sw.Translation is
2893 Place_Unix_Switches (Sw.Unix_String);
2894 if Arg (SwP + 1) = '=' then
2895 Put (Standard_Error,
2896 "qualifier options ignored: ");
2897 Put_Line (Standard_Error, Arg.all);
2900 when T_Directories =>
2901 if SwP + 1 > Arg'Last then
2902 Put (Standard_Error,
2903 "missing directories for: ");
2904 Put_Line (Standard_Error, Arg.all);
2905 Errors := Errors + 1;
2907 elsif Arg (SwP + 2) /= '(' then
2911 elsif Arg (Arg'Last) /= ')' then
2913 -- Remove spaces from a comma separated list
2914 -- of file names and adjust control
2915 -- variables accordingly.
2917 if Arg_Num < Argument_Count and then
2918 (Argv (Argv'Last) = ',' xor
2919 Argument (Arg_Num + 1)
2920 (Argument (Arg_Num + 1)'First) = ',')
2922 Argv := new String'(Argv.all
2923 & Argument (Arg_Num + 1));
2924 Arg_Num := Arg_Num + 1;
2925 Arg_Idx := Argv'First;
2927 := Get_Arg_End (Argv.all, Arg_Idx);
2929 (Argv (Arg_Idx .. Next_Arg_Idx));
2930 goto Tryagain_After_Coalesce;
2933 Put (Standard_Error,
2934 "incorrectly parenthesized " &
2935 "or malformed argument: ");
2936 Put_Line (Standard_Error, Arg.all);
2937 Errors := Errors + 1;
2941 Endp := Arg'Last - 1;
2944 while SwP <= Endp loop
2946 Dir_Is_Wild : Boolean := False;
2947 Dir_Maybe_Is_Wild : Boolean := False;
2948 Dir_List : String_Access_List_Access;
2953 and then Arg (P2 + 1) /= ','
2956 -- A wildcard directory spec on VMS
2957 -- will contain either * or % or ...
2959 if Arg (P2) = '*' then
2960 Dir_Is_Wild := True;
2962 elsif Arg (P2) = '%' then
2963 Dir_Is_Wild := True;
2965 elsif Dir_Maybe_Is_Wild
2966 and then Arg (P2) = '.'
2967 and then Arg (P2 + 1) = '.'
2969 Dir_Is_Wild := True;
2970 Dir_Maybe_Is_Wild := False;
2972 elsif Dir_Maybe_Is_Wild then
2973 Dir_Maybe_Is_Wild := False;
2975 elsif Arg (P2) = '.'
2976 and then Arg (P2 + 1) = '.'
2978 Dir_Maybe_Is_Wild := True;
2985 if (Dir_Is_Wild) then
2986 Dir_List := To_Canonical_File_List
2987 (Arg (SwP .. P2), True);
2989 for I in Dir_List.all'Range loop
2990 Place_Unix_Switches (Sw.Unix_String);
2991 Place_Lower (Dir_List.all (I).all);
2994 Place_Unix_Switches (Sw.Unix_String);
2995 Place_Lower (To_Canonical_Dir_Spec
2996 (Arg (SwP .. P2), False).all);
3004 if SwP + 1 > Arg'Last then
3005 Put (Standard_Error,
3006 "missing directory for: ");
3007 Put_Line (Standard_Error, Arg.all);
3008 Errors := Errors + 1;
3011 Place_Unix_Switches (Sw.Unix_String);
3013 -- Some switches end in "=". No space here
3016 (Sw.Unix_String'Last) /= '='
3021 Place_Lower (To_Canonical_Dir_Spec
3022 (Arg (SwP + 2 .. Arg'Last), False).all);
3026 if SwP + 1 > Arg'Last then
3027 Put (Standard_Error, "missing file for: ");
3028 Put_Line (Standard_Error, Arg.all);
3029 Errors := Errors + 1;
3032 Place_Unix_Switches (Sw.Unix_String);
3034 -- Some switches end in "=". No space here
3037 (Sw.Unix_String'Last) /= '='
3042 Place_Lower (To_Canonical_File_Spec
3043 (Arg (SwP + 2 .. Arg'Last)).all);
3047 if OK_Integer (Arg (SwP + 2 .. Arg'Last)) then
3048 Place_Unix_Switches (Sw.Unix_String);
3049 Place (Arg (SwP + 2 .. Arg'Last));
3052 Put (Standard_Error, "argument for ");
3053 Put (Standard_Error, Sw.Name.all);
3054 Put_Line (Standard_Error, " must be numeric");
3055 Errors := Errors + 1;
3058 when T_Alphanumplus =>
3060 OK_Alphanumerplus (Arg (SwP + 2 .. Arg'Last))
3062 Place_Unix_Switches (Sw.Unix_String);
3063 Place (Arg (SwP + 2 .. Arg'Last));
3066 Put (Standard_Error, "argument for ");
3067 Put (Standard_Error, Sw.Name.all);
3068 Put_Line (Standard_Error,
3069 " must be alphanumeric");
3070 Errors := Errors + 1;
3075 -- A String value must be extended to the
3076 -- end of the Argv, otherwise strings like
3077 -- "foo/bar" get split at the slash.
3079 -- The begining and ending of the string
3080 -- are flagged with embedded nulls which
3081 -- are removed when building the Spawn
3082 -- call. Nulls are use because they won't
3083 -- show up in a /? output. Quotes aren't
3084 -- used because that would make it difficult
3087 Place_Unix_Switches (Sw.Unix_String);
3088 if Next_Arg_Idx /= Argv'Last then
3089 Next_Arg_Idx := Argv'Last;
3091 (Argv (Arg_Idx .. Next_Arg_Idx));
3094 while SwP < Arg'Last and then
3095 Arg (SwP + 1) /= '=' loop
3100 Place (Arg (SwP + 2 .. Arg'Last));
3105 -- Output -largs/-bargs/-cargs
3108 Place (Sw.Unix_String
3109 (Sw.Unix_String'First ..
3110 Sw.Unix_String'First + 5));
3112 -- Set source of new commands, also setting this
3113 -- non-null indicates that we are in the special
3114 -- commands mode for processing the -xargs case.
3116 Make_Commands_Active :=
3119 (Sw.Unix_String'First + 7 ..
3120 Sw.Unix_String'Last),
3124 if SwP + 1 > Arg'Last then
3125 Place_Unix_Switches (Sw.Options.Unix_String);
3128 elsif Arg (SwP + 2) /= '(' then
3132 elsif Arg (Arg'Last) /= ')' then
3133 Put (Standard_Error,
3134 "incorrectly parenthesized argument: ");
3135 Put_Line (Standard_Error, Arg.all);
3136 Errors := Errors + 1;
3141 Endp := Arg'Last - 1;
3144 while SwP <= Endp loop
3148 and then Arg (P2 + 1) /= ','
3153 -- Option name is in Arg (SwP .. P2)
3155 Opt := Matching_Name (Arg (SwP .. P2),
3159 Place_Unix_Switches (Opt.Unix_String);
3167 (new String'(Sw.Unix_String.all & Arg.all));
3174 Arg_Idx := Next_Arg_Idx + 1;
3177 exit when Arg_Idx > Argv'Last;
3182 Arg_Num := Arg_Num + 1;
3185 if Display_Command then
3186 Put (Standard_Error, "generated command -->");
3187 Put (Standard_Error, String (Buffer.Table (1 .. Buffer.Last)));
3188 Put (Standard_Error, "<--");
3189 New_Line (Standard_Error);
3193 -- Gross error checking that the number of parameters is correct.
3194 -- Not applicable to Unlimited_Files parameters.
3196 if not ((Param_Count = Command.Params'Length - 1 and then
3197 Command.Params (Param_Count + 1) = Unlimited_Files)
3198 or else (Param_Count <= Command.Params'Length))
3200 Put_Line (Standard_Error,
3201 "Parameter count of "
3202 & Integer'Image (Param_Count)
3203 & " not equal to expected "
3204 & Integer'Image (Command.Params'Length));
3205 Put (Standard_Error, "usage: ");
3206 Put_Line (Standard_Error, Command.Usage.all);
3207 Errors := Errors + 1;
3213 -- Prepare arguments for a call to spawn, filtering out
3214 -- embedded nulls place there to delineate strings.
3217 Pname_Ptr : Natural;
3218 Args : Argument_List (1 .. 500);
3221 Exec_Path : String_Access;
3222 Inside_Nul : Boolean := False;
3223 Arg : String (1 .. 1024);
3229 while Pname_Ptr < Buffer.Last
3230 and then Buffer.Table (Pname_Ptr + 1) /= ' '
3232 Pname_Ptr := Pname_Ptr + 1;
3235 P1 := Pname_Ptr + 2;
3237 Arg (Arg_Ctr) := Buffer.Table (P1);
3240 while P1 <= Buffer.Last loop
3242 if Buffer.Table (P1) = ASCII.NUL then
3244 Inside_Nul := False;
3250 if Buffer.Table (P1) = ' ' and then not Inside_Nul then
3252 Arg_Ctr := Arg_Ctr + 1;
3253 Arg (Arg_Ctr) := Buffer.Table (P1);
3259 while P2 < Buffer.Last
3260 and then (Buffer.Table (P2 + 1) /= ' ' or else
3264 Arg_Ctr := Arg_Ctr + 1;
3265 Arg (Arg_Ctr) := Buffer.Table (P2);
3266 if Buffer.Table (P2) = ASCII.NUL then
3267 Arg_Ctr := Arg_Ctr - 1;
3269 Inside_Nul := False;
3276 Args (Nargs) := new String'(String (Arg (1 .. Arg_Ctr)));
3279 Arg (Arg_Ctr) := Buffer.Table (P1);
3283 Exec_Path := Locate_Exec_On_Path
3284 (String (Buffer.Table (1 .. Pname_Ptr)));
3286 if Exec_Path = null then
3287 Put_Line (Standard_Error,
3289 & String (Buffer.Table (1 .. Pname_Ptr)));
3294 := Exit_Status (Spawn (Exec_Path.all, Args (1 .. Nargs)));
3303 Set_Exit_Status (Failure);
3306 Set_Exit_Status (My_Exit_Status);