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 GNAT BIND --
167 ----------------------------
169 S_Bind_Bind : aliased constant S := "/BIND_FILE=" &
175 S_Bind_Build : aliased constant S := "/BUILD_LIBRARY=|" &
178 S_Bind_Current : aliased constant S := "/CURRENT_DIRECTORY " &
181 S_Bind_Debug : aliased constant S := "/DEBUG=" &
197 S_Bind_DebugX : aliased constant S := "/NODEBUG " &
200 S_Bind_Elab : aliased constant S := "/ELABORATION_DEPENDENCIES " &
203 S_Bind_Error : aliased constant S := "/ERROR_LIMIT=#" &
206 S_Bind_Full : aliased constant S := "/FULL_ELABORATION " &
209 S_Bind_Library : aliased constant S := "/LIBRARY_SEARCH=*" &
212 S_Bind_Linker : aliased constant S := "/LINKER_OPTION_LIST " &
215 S_Bind_Main : aliased constant S := "/MAIN " &
218 S_Bind_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
221 S_Bind_Nostlib : aliased constant S := "/NOSTD_LIBRARIES " &
224 S_Bind_Object : aliased constant S := "/OBJECT_LIST " &
227 S_Bind_Order : aliased constant S := "/ORDER_OF_ELABORATION " &
230 S_Bind_Output : aliased constant S := "/OUTPUT=@" &
233 S_Bind_OutputX : aliased constant S := "/NOOUTPUT " &
236 S_Bind_Pess : aliased constant S := "/PESSIMISTIC_ELABORATION " &
239 S_Bind_Read : aliased constant S := "/READ_SOURCES=" &
247 S_Bind_ReadX : aliased constant S := "/NOREAD_SOURCES " &
250 S_Bind_Rename : aliased constant S := "/RENAME_MAIN " &
253 S_Bind_Report : aliased constant S := "/REPORT_ERRORS=" &
261 S_Bind_ReportX : aliased constant S := "/NOREPORT_ERRORS " &
264 S_Bind_Search : aliased constant S := "/SEARCH=*" &
267 S_Bind_Shared : aliased constant S := "/SHARED " &
270 S_Bind_Source : aliased constant S := "/SOURCE_SEARCH=*" &
273 S_Bind_Time : aliased constant S := "/TIME_STAMP_CHECK " &
276 S_Bind_Verbose : aliased constant S := "/VERBOSE " &
279 S_Bind_Warn : aliased constant S := "/WARNINGS=" &
287 S_Bind_WarnX : aliased constant S := "/NOWARNINGS " &
290 Bind_Switches : aliased constant Switches := (
292 S_Bind_Build 'Access,
293 S_Bind_Current 'Access,
294 S_Bind_Debug 'Access,
295 S_Bind_DebugX 'Access,
297 S_Bind_Error 'Access,
299 S_Bind_Library 'Access,
300 S_Bind_Linker 'Access,
302 S_Bind_Nostinc 'Access,
303 S_Bind_Nostlib 'Access,
304 S_Bind_Object 'Access,
305 S_Bind_Order 'Access,
306 S_Bind_Output 'Access,
307 S_Bind_OutputX 'Access,
310 S_Bind_ReadX 'Access,
311 S_Bind_Rename 'Access,
312 S_Bind_Report 'Access,
313 S_Bind_ReportX 'Access,
314 S_Bind_Search 'Access,
315 S_Bind_Shared 'Access,
316 S_Bind_Source 'Access,
318 S_Bind_Verbose 'Access,
320 S_Bind_WarnX 'Access);
322 ----------------------------
323 -- Switches for GNAT CHOP --
324 ----------------------------
326 S_Chop_Comp : aliased constant S := "/COMPILATION " &
329 S_Chop_File : aliased constant S := "/FILE_NAME_MAX_LENGTH=#" &
332 S_Chop_Help : aliased constant S := "/HELP " &
335 S_Chop_Over : aliased constant S := "/OVERWRITE " &
338 S_Chop_Quiet : aliased constant S := "/QUIET " &
341 S_Chop_Ref : aliased constant S := "/REFERENCE " &
344 S_Chop_Verb : aliased constant S := "/VERBOSE " &
347 Chop_Switches : aliased constant Switches := (
352 S_Chop_Quiet 'Access,
354 S_Chop_Verb 'Access);
356 -------------------------------
357 -- Switches for GNAT COMPILE --
358 -------------------------------
360 S_GCC_Ada_83 : aliased constant S := "/83 " &
363 S_GCC_Ada_95 : aliased constant S := "/95 " &
366 S_GCC_Asm : aliased constant S := "/ASM " &
369 S_GCC_Checks : aliased constant S := "/CHECKS=" &
371 "-gnato,!-gnatE,!-gnatp " &
383 S_GCC_ChecksX : aliased constant S := "/NOCHECKS " &
384 "-gnatp,!-gnato,!-gnatE";
386 S_GCC_Compres : aliased constant S := "/COMPRESS_NAMES " &
389 S_GCC_Current : aliased constant S := "/CURRENT_DIRECTORY " &
392 S_GCC_Debug : aliased constant S := "/DEBUG=" &
406 S_GCC_DebugX : aliased constant S := "/NODEBUG " &
409 S_GCC_Dist : aliased constant S := "/DISTRIBUTION_STUBS=" &
415 S_GCC_DistX : aliased constant S := "/NODISTRIBUTION_STUBS " &
418 S_GCC_Error : aliased constant S := "/ERROR_LIMIT=#" &
421 S_GCC_ErrorX : aliased constant S := "/NOERROR_LIMIT " &
424 S_GCC_Expand : aliased constant S := "/EXPAND_SOURCE " &
427 S_GCC_Extend : aliased constant S := "/EXTENSIONS_ALLOWED " &
430 S_GCC_File : aliased constant S := "/FILE_NAME_MAX_LENGTH=#" &
433 S_GCC_Force : aliased constant S := "/FORCE_ALI " &
436 S_GCC_Ident : aliased constant S := "/IDENTIFIER_CHARACTER_SET=" &
458 S_GCC_IdentX : aliased constant S := "/NOIDENTIFIER_CHARACTER_SET " &
461 S_GCC_Inline : aliased constant S := "/INLINE=" &
467 S_GCC_InlineX : aliased constant S := "/NOINLINE " &
470 S_GCC_List : aliased constant S := "/LIST " &
473 S_GCC_Noload : aliased constant S := "/NOLOAD " &
476 S_GCC_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
479 S_GCC_Opt : aliased constant S := "/OPTIMIZE=" &
481 "-O2,!-O0,!-O1,!-O3 " &
483 "-O0,!-O1,!-O2,!-O3 " &
485 "-O1,!-O0,!-O2,!-O3 " &
487 "-O1,!-O0,!-O2,!-O3 " &
491 "-O3,!-O0,!-O1,!-O2";
493 S_GCC_OptX : aliased constant S := "/NOOPTIMIZE " &
494 "-O0,!-O1,!-O2,!-O3";
496 S_GCC_Report : aliased constant S := "/REPORT_ERRORS=" &
508 S_GCC_ReportX : aliased constant S := "/NOREPORT_ERRORS " &
511 S_GCC_Repinfo : aliased constant S := "/REPRESENTATION_INFO=" &
523 S_GCC_RepinfX : aliased constant S := "/NOREPRESENTATION_INFO " &
526 S_GCC_Search : aliased constant S := "/SEARCH=*" &
529 S_GCC_Style : aliased constant S := "/STYLE_CHECKS=" &
574 "ORDERED_SUBPROGRAMS " &
587 S_GCC_StyleX : aliased constant S := "/NOSTYLE_CHECKS " &
590 S_GCC_Syntax : aliased constant S := "/SYNTAX_ONLY " &
593 S_GCC_Trace : aliased constant S := "/TRACE_UNITS " &
596 S_GCC_Tree : aliased constant S := "/TREE_OUTPUT " &
599 S_GCC_Trys : aliased constant S := "/TRY_SEMANTICS " &
602 S_GCC_Units : aliased constant S := "/UNITS_LIST " &
605 S_GCC_Unique : aliased constant S := "/UNIQUE_ERROR_TAG " &
608 S_GCC_Upcase : aliased constant S := "/UPPERCASE_EXTERNALS " &
611 S_GCC_Valid : aliased constant S := "/VALIDITY_CHECKING=" &
619 S_GCC_Verbose : aliased constant S := "/VERBOSE " &
622 S_GCC_Warn : aliased constant S := "/WARNINGS=" &
624 "!-gnatws,!-gnatwe " &
643 "NOIMPLEMENTATION " &
666 S_GCC_WarnX : aliased constant S := "/NOWARNINGS " &
669 S_GCC_Wide : aliased constant S := "/WIDE_CHARACTER_ENCODING=" &
685 S_GCC_WideX : aliased constant S := "/NOWIDE_CHARACTER_ENCODING " &
688 S_GCC_Xdebug : aliased constant S := "/XDEBUG " &
691 S_GCC_Xref : aliased constant S := "/XREF=" &
697 GCC_Switches : aliased constant Switches := (
698 S_GCC_Ada_83 'Access,
699 S_GCC_Ada_95 'Access,
701 S_GCC_Checks 'Access,
702 S_GCC_ChecksX 'Access,
703 S_GCC_Compres 'Access,
704 S_GCC_Current 'Access,
706 S_GCC_DebugX 'Access,
710 S_GCC_ErrorX 'Access,
711 S_GCC_Expand 'Access,
712 S_GCC_Extend 'Access,
716 S_GCC_IdentX 'Access,
717 S_GCC_Inline 'Access,
718 S_GCC_InlineX 'Access,
720 S_GCC_Noload 'Access,
721 S_GCC_Nostinc 'Access,
724 S_GCC_Report 'Access,
725 S_GCC_ReportX 'Access,
726 S_GCC_Repinfo 'Access,
727 S_GCC_RepinfX 'Access,
728 S_GCC_Search 'Access,
730 S_GCC_StyleX 'Access,
731 S_GCC_Syntax 'Access,
736 S_GCC_Unique 'Access,
737 S_GCC_Upcase 'Access,
739 S_GCC_Verbose 'Access,
744 S_GCC_Xdebug 'Access,
747 ----------------------------
748 -- Switches for GNAT ELIM --
749 ----------------------------
751 S_Elim_All : aliased constant S := "/ALL " &
754 S_Elim_Miss : aliased constant S := "/MISSED " &
757 S_Elim_Verb : aliased constant S := "/VERBOSE " &
760 Elim_Switches : aliased constant Switches := (
763 S_Elim_Verb 'Access);
765 ----------------------------
766 -- Switches for GNAT FIND --
767 ----------------------------
769 S_Find_All : aliased constant S := "/ALL_FILES " &
772 S_Find_Expr : aliased constant S := "/EXPRESSIONS " &
775 S_Find_Full : aliased constant S := "/FULL_PATHNAME " &
778 S_Find_Ignore : aliased constant S := "/IGNORE_LOCALS " &
781 S_Find_Object : aliased constant S := "/OBJECT_SEARCH=*" &
784 S_Find_Print : aliased constant S := "/PRINT_LINES " &
787 S_Find_Project : aliased constant S := "/PROJECT=@" &
790 S_Find_Ref : aliased constant S := "/REFERENCES " &
793 S_Find_Search : aliased constant S := "/SEARCH=*" &
796 S_Find_Source : aliased constant S := "/SOURCE_SEARCH=*" &
799 Find_Switches : aliased constant Switches := (
803 S_Find_Ignore 'Access,
804 S_Find_Object 'Access,
805 S_Find_Print 'Access,
806 S_Find_Project 'Access,
808 S_Find_Search 'Access,
809 S_Find_Source 'Access);
811 ------------------------------
812 -- Switches for GNAT KRUNCH --
813 ------------------------------
815 S_Krunch_Count : aliased constant S := "/COUNT=#" &
818 Krunch_Switches : aliased constant Switches := (1 .. 1 =>
819 S_Krunch_Count 'Access);
821 -------------------------------
822 -- Switches for GNAT LIBRARY --
823 -------------------------------
825 S_Lbr_Config : aliased constant S := "/CONFIG=@" &
828 S_Lbr_Create : aliased constant S := "/CREATE=%" &
831 S_Lbr_Delete : aliased constant S := "/DELETE=%" &
834 S_Lbr_Set : aliased constant S := "/SET=%" &
837 Lbr_Switches : aliased constant Switches := (
838 S_Lbr_Config 'Access,
839 S_Lbr_Create 'Access,
840 S_Lbr_Delete 'Access,
843 ----------------------------
844 -- Switches for GNAT LINK --
845 ----------------------------
847 S_Link_Bind : aliased constant S := "/BIND_FILE=" &
853 S_Link_Debug : aliased constant S := "/DEBUG=" &
863 S_Link_Execut : aliased constant S := "/EXECUTABLE=@" &
866 S_Link_Ident : aliased constant S := "/IDENTIFICATION=" & '"' &
867 "--for-linker=IDENT=" &
870 S_Link_Nocomp : aliased constant S := "/NOCOMPILE " &
873 S_Link_Nofiles : aliased constant S := "/NOSTART_FILES " &
876 S_Link_Noinhib : aliased constant S := "/NOINHIBIT-EXEC " &
877 "--for-linker=--noinhibit-exec";
879 S_Link_Static : aliased constant S := "/STATIC " &
880 "--for-linker=-static";
882 S_Link_Verb : aliased constant S := "/VERBOSE " &
885 S_Link_ZZZZZ : aliased constant S := "/<other> " &
888 Link_Switches : aliased constant Switches := (
890 S_Link_Debug 'Access,
891 S_Link_Execut 'Access,
892 S_Link_Ident 'Access,
893 S_Link_Nocomp 'Access,
894 S_Link_Nofiles 'Access,
895 S_Link_Noinhib 'Access,
896 S_Link_Static 'Access,
898 S_Link_ZZZZZ 'Access);
900 ----------------------------
901 -- Switches for GNAT LIST --
902 ----------------------------
904 S_List_All : aliased constant S := "/ALL_UNITS " &
907 S_List_Current : aliased constant S := "/CURRENT_DIRECTORY " &
910 S_List_Depend : aliased constant S := "/DEPENDENCIES " &
913 S_List_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
916 S_List_Object : aliased constant S := "/OBJECT_SEARCH=*" &
919 S_List_Output : aliased constant S := "/OUTPUT=" &
931 S_List_Search : aliased constant S := "/SEARCH=*" &
934 S_List_Source : aliased constant S := "/SOURCE_SEARCH=*" &
937 List_Switches : aliased constant Switches := (
939 S_List_Current 'Access,
940 S_List_Depend 'Access,
941 S_List_Nostinc 'Access,
942 S_List_Object 'Access,
943 S_List_Output 'Access,
944 S_List_Search 'Access,
945 S_List_Source 'Access);
947 ----------------------------
948 -- Switches for GNAT MAKE --
949 ----------------------------
951 S_Make_All : aliased constant S := "/ALL_FILES " &
954 S_Make_Bind : aliased constant S := "/BINDER_QUALIFIERS=?" &
957 S_Make_Comp : aliased constant S := "/COMPILER_QUALIFIERS=?" &
960 S_Make_Cond : aliased constant S := "/CONDITIONAL_SOURCE_SEARCH=*" &
963 S_Make_Cont : aliased constant S := "/CONTINUE_ON_ERROR " &
966 S_Make_Current : aliased constant S := "/CURRENT_DIRECTORY " &
969 S_Make_Dep : aliased constant S := "/DEPENDENCIES_LIST " &
972 S_Make_Doobj : aliased constant S := "/DO_OBJECT_CHECK " &
975 S_Make_Execut : aliased constant S := "/EXECUTABLE=@" &
978 S_Make_Force : aliased constant S := "/FORCE_COMPILE " &
981 S_Make_Inplace : aliased constant S := "/IN_PLACE " &
984 S_Make_Library : aliased constant S := "/LIBRARY_SEARCH=*" &
987 S_Make_Link : aliased constant S := "/LINKER_QUALIFIERS=?" &
990 S_Make_Minimal : aliased constant S := "/MINIMAL_RECOMPILATION " &
993 S_Make_Nolink : aliased constant S := "/NOLINK " &
996 S_Make_Nostinc : aliased constant S := "/NOSTD_INCLUDES " &
999 S_Make_Nostlib : aliased constant S := "/NOSTD_LIBRARIES " &
1002 S_Make_Object : aliased constant S := "/OBJECT_SEARCH=*" &
1005 S_Make_Proc : aliased constant S := "/PROCESSES=#" &
1008 S_Make_Nojobs : aliased constant S := "/NOPROCESSES " &
1011 S_Make_Quiet : aliased constant S := "/QUIET " &
1014 S_Make_Reason : aliased constant S := "/REASONS " &
1017 S_Make_Search : aliased constant S := "/SEARCH=*" &
1020 S_Make_Skip : aliased constant S := "/SKIP_MISSING=*" &
1023 S_Make_Source : aliased constant S := "/SOURCE_SEARCH=*" &
1026 S_Make_Verbose : aliased constant S := "/VERBOSE " &
1029 Make_Switches : aliased constant Switches := (
1031 S_Make_Bind 'Access,
1032 S_Make_Comp 'Access,
1033 S_Make_Cond 'Access,
1034 S_Make_Cont 'Access,
1035 S_Make_Current 'Access,
1037 S_Make_Doobj 'Access,
1038 S_Make_Execut 'Access,
1039 S_Make_Force 'Access,
1040 S_Make_Inplace 'Access,
1041 S_Make_Library 'Access,
1042 S_Make_Link 'Access,
1043 S_Make_Minimal 'Access,
1044 S_Make_Nolink 'Access,
1045 S_Make_Nostinc 'Access,
1046 S_Make_Nostlib 'Access,
1047 S_Make_Object 'Access,
1048 S_Make_Proc 'Access,
1049 S_Make_Nojobs 'Access,
1050 S_Make_Quiet 'Access,
1051 S_Make_Reason 'Access,
1052 S_Make_Search 'Access,
1053 S_Make_Skip 'Access,
1054 S_Make_Source 'Access,
1055 S_Make_Verbose 'Access);
1057 ----------------------------------
1058 -- Switches for GNAT PREPROCESS --
1059 ----------------------------------
1061 S_Prep_Blank : aliased constant S := "/BLANK_LINES " &
1064 S_Prep_Com : aliased constant S := "/COMMENTS " &
1067 S_Prep_Ref : aliased constant S := "/REFERENCE " &
1070 S_Prep_Remove : aliased constant S := "/REMOVE " &
1073 S_Prep_Symbols : aliased constant S := "/SYMBOLS " &
1076 S_Prep_Undef : aliased constant S := "/UNDEFINED " &
1079 S_Prep_Verbose : aliased constant S := "/VERBOSE " &
1082 S_Prep_Version : aliased constant S := "/VERSION " &
1085 Prep_Switches : aliased constant Switches := (
1086 S_Prep_Blank 'Access,
1089 S_Prep_Remove 'Access,
1090 S_Prep_Symbols 'Access,
1091 S_Prep_Undef 'Access,
1092 S_Prep_Verbose 'Access,
1093 S_Prep_Version 'Access);
1095 ------------------------------
1096 -- Switches for GNAT SHARED --
1097 ------------------------------
1099 S_Shared_Debug : aliased constant S := "/DEBUG=" &
1109 S_Shared_Image : aliased constant S := "/IMAGE=@" &
1112 S_Shared_Ident : aliased constant S := "/IDENTIFICATION=" & '"' &
1113 "--for-linker=IDENT=" &
1116 S_Shared_Nofiles : aliased constant S := "/NOSTART_FILES " &
1119 S_Shared_Noinhib : aliased constant S := "/NOINHIBIT-IMAGE " &
1120 "--for-linker=--noinhibit-exec";
1122 S_Shared_Verb : aliased constant S := "/VERBOSE " &
1125 S_Shared_ZZZZZ : aliased constant S := "/<other> " &
1128 Shared_Switches : aliased constant Switches := (
1129 S_Shared_Debug 'Access,
1130 S_Shared_Image 'Access,
1131 S_Shared_Ident 'Access,
1132 S_Shared_Nofiles 'Access,
1133 S_Shared_Noinhib 'Access,
1134 S_Shared_Verb 'Access,
1135 S_Shared_ZZZZZ 'Access);
1137 --------------------------------
1138 -- Switches for GNAT STANDARD --
1139 --------------------------------
1141 Standard_Switches : aliased constant Switches := (1 .. 0 => null);
1143 ----------------------------
1144 -- Switches for GNAT STUB --
1145 ----------------------------
1147 S_Stub_Current : aliased constant S := "/CURRENT_DIRECTORY " &
1150 S_Stub_Full : aliased constant S := "/FULL " &
1153 S_Stub_Header : aliased constant S := "/HEADER=" &
1159 S_Stub_Indent : aliased constant S := "/INDENTATION=#" &
1162 S_Stub_Length : aliased constant S := "/LINE_LENGTH=#" &
1165 S_Stub_Quiet : aliased constant S := "/QUIET " &
1168 S_Stub_Search : aliased constant S := "/SEARCH=*" &
1171 S_Stub_Tree : aliased constant S := "/TREE_FILE=" &
1179 S_Stub_Verbose : aliased constant S := "/VERBOSE " &
1182 Stub_Switches : aliased constant Switches := (
1183 S_Stub_Current 'Access,
1184 S_Stub_Full 'Access,
1185 S_Stub_Header 'Access,
1186 S_Stub_Indent 'Access,
1187 S_Stub_Length 'Access,
1188 S_Stub_Quiet 'Access,
1189 S_Stub_Search 'Access,
1190 S_Stub_Tree 'Access,
1191 S_Stub_Verbose 'Access);
1193 ------------------------------
1194 -- Switches for GNAT SYSTEM --
1195 ------------------------------
1197 System_Switches : aliased constant Switches := (1 .. 0 => null);
1199 ----------------------------
1200 -- Switches for GNAT XREF --
1201 ----------------------------
1203 S_Xref_All : aliased constant S := "/ALL_FILES " &
1206 S_Xref_Full : aliased constant S := "/FULL_PATHNAME " &
1209 S_Xref_Global : aliased constant S := "/IGNORE_LOCALS " &
1212 S_Xref_Object : aliased constant S := "/OBJECT_SEARCH=*" &
1215 S_Xref_Project : aliased constant S := "/PROJECT=@" &
1218 S_Xref_Search : aliased constant S := "/SEARCH=*" &
1221 S_Xref_Source : aliased constant S := "/SOURCE_SEARCH=*" &
1224 S_Xref_Output : aliased constant S := "/UNUSED " &
1227 Xref_Switches : aliased constant Switches := (
1229 S_Xref_Full 'Access,
1230 S_Xref_Global 'Access,
1231 S_Xref_Object 'Access,
1232 S_Xref_Project 'Access,
1233 S_Xref_Search 'Access,
1234 S_Xref_Source 'Access,
1235 S_Xref_Output 'Access);
1241 -- The command table contains an entry for each command recognized by
1242 -- GNATCmd. The entries are represented by an array of records.
1244 type Parameter_Type is
1245 -- A parameter is defined as a whitespace bounded string, not begining
1246 -- with a slash. (But see note under FILES_OR_WILDCARD).
1248 -- A required file or directory parameter.
1251 -- An optional file or directory parameter.
1254 -- A parameter that's passed through as is (not canonicalized)
1257 -- An unlimited number of writespace separate file or directory
1258 -- parameters including wildcard specifications.
1261 -- A comma separated list of files and/or wildcard file specifications.
1262 -- A comma preceded by or followed by whitespace is considered as a
1263 -- single comma character w/o whitespace.
1265 type Parameter_Array is array (Natural range <>) of Parameter_Type;
1266 type Parameter_Ref is access all Parameter_Array;
1268 type Command_Entry is record
1270 -- Command name for GNAT xxx command
1273 -- A usage string, used for error messages
1275 Unixcmd : String_Ptr;
1276 -- Corresponding Unix command
1278 Switches : Switches_Ptr;
1279 -- Pointer to array of switch strings
1281 Params : Parameter_Ref;
1282 -- Describes the allowable types of parameters.
1283 -- Params (1) is the type of the first parameter, etc.
1284 -- An empty parameter array means this command takes no parameters.
1286 Defext : String (1 .. 3);
1287 -- Default extension. If non-blank, then this extension is supplied by
1288 -- default as the extension for any file parameter which does not have
1289 -- an extension already.
1292 -------------------------
1293 -- INTERNAL STRUCTURES --
1294 -------------------------
1296 -- The switches and commands are defined by strings in the previous
1297 -- section so that they are easy to modify, but internally, they are
1298 -- kept in a more conveniently accessible form described in this
1301 -- Commands, command qualifers and options have a similar common format
1302 -- so that searching for matching names can be done in a common manner.
1304 type Item_Id is (Id_Command, Id_Switch, Id_Option);
1306 type Translation_Type is
1309 -- A qualifier with no options.
1310 -- Example: GNAT MAKE /VERBOSE
1313 -- A qualifier followed by a list of directories
1314 -- Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
1317 -- A qualifier followed by one directory
1318 -- Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
1321 -- A quailifier followed by a filename
1322 -- Example: GNAT LINK /EXECUTABLE=FOO.EXE
1325 -- A qualifier followed by a numeric value.
1326 -- Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
1329 -- A qualifier followed by a quoted string. Only used by
1330 -- /IDENTIFICATION qualfier.
1331 -- Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
1334 -- A qualifier followed by a list of options.
1335 -- Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
1338 -- A qualifier followed by a list. Only used for
1339 -- MAKE /COMPILER_QUALIFIERS /BINDER_QUALIFIERS /LINKER_QUALIFIERS
1340 -- (gnatmake -cargs -bargs -largs )
1341 -- Example: GNAT MAKE ... /LINKER_QUALIFIERS /VERBOSE FOOBAR.OBJ
1344 -- A qualifier passed directly to the linker. Only used
1345 -- for LINK and SHARED if no other match is found.
1346 -- Example: GNAT LINK FOO.ALI /SYSSHR
1349 -- A qualifier followed by a legal linker symbol prefix. Only used
1350 -- for BIND /BUILD_LIBRARY (gnatbind -Lxyz).
1351 -- Example: GNAT BIND /BUILD_LIBRARY=foobar
1354 type Item (Id : Item_Id);
1355 type Item_Ptr is access all Item;
1357 type Item (Id : Item_Id) is record
1359 -- Name of the command, switch (with slash) or option
1362 -- Pointer to next item on list, always has the same Id value
1364 Unix_String : String_Ptr;
1365 -- Corresponding Unix string. For a command, this is the unix command
1366 -- name and possible default switches. For a switch or option it is
1367 -- the unix switch string.
1373 Switches : Item_Ptr;
1374 -- Pointer to list of switch items for the command, linked
1375 -- through the Next fields with null terminating the list.
1378 -- Usage information, used only for errors and the default
1379 -- list of commands output.
1381 Params : Parameter_Ref;
1382 -- Array of parameters
1384 Defext : String (1 .. 3);
1385 -- Default extension. If non-blank, then this extension is
1386 -- supplied by default as the extension for any file parameter
1387 -- which does not have an extension already.
1391 Translation : Translation_Type;
1392 -- Type of switch translation. For all cases, except Options,
1393 -- this is the only field needed, since the Unix translation
1394 -- is found in Unix_String.
1397 -- For the Options case, this field is set to point to a list
1398 -- of options item (for this case Unix_String is null in the
1399 -- main switch item). The end of the list is marked by null.
1404 -- No special fields needed, since Name and Unix_String are
1405 -- sufficient to completely described an option.
1410 subtype Command_Item is Item (Id_Command);
1411 subtype Switch_Item is Item (Id_Switch);
1412 subtype Option_Item is Item (Id_Option);
1414 ----------------------------------
1415 -- Declarations for GNATCMD use --
1416 ----------------------------------
1418 Commands : Item_Ptr;
1419 -- Pointer to head of list of command items, one for each command, with
1420 -- the end of the list marked by a null pointer.
1422 Last_Command : Item_Ptr;
1423 -- Pointer to last item in Commands list
1425 Normal_Exit : exception;
1426 -- Raise this exception for normal program termination
1428 Error_Exit : exception;
1429 -- Raise this exception if error detected
1431 Errors : Natural := 0;
1432 -- Count errors detected
1435 -- Pointer to command item for current command
1437 Make_Commands_Active : Item_Ptr := null;
1438 -- Set to point to Command entry for COMPILE, BIND, or LINK as appropriate
1439 -- if a COMMANDS_TRANSLATION switch has been encountered while processing
1442 My_Exit_Status : Exit_Status := Success;
1444 package Buffer is new Table.Table (
1445 Table_Component_Type => Character,
1446 Table_Index_Type => Integer,
1447 Table_Low_Bound => 1,
1448 Table_Initial => 4096,
1449 Table_Increment => 2,
1450 Table_Name => "Buffer");
1452 Param_Count : Natural := 0;
1453 -- Number of parameter arguments so far
1458 Display_Command : Boolean := False;
1459 -- Set true if /? switch causes display of generated command
1461 -----------------------
1462 -- Local Subprograms --
1463 -----------------------
1465 function Init_Object_Dirs return String_Ptr;
1467 function Invert_Sense (S : String) return String_Ptr;
1468 -- Given a unix switch string S, computes the inverse (adding or
1469 -- removing ! characters as required), and returns a pointer to
1470 -- the allocated result on the heap.
1472 function Is_Extensionless (F : String) return Boolean;
1473 -- Returns true if the filename has no extension.
1475 function Match (S1, S2 : String) return Boolean;
1476 -- Determines whether S1 and S2 match. This is a case insensitive match.
1478 function Match_Prefix (S1, S2 : String) return Boolean;
1479 -- Determines whether S1 matches a prefix of S2. This is also a case
1480 -- insensitive match (for example Match ("AB","abc") is True).
1482 function Matching_Name
1485 Quiet : Boolean := False)
1487 -- Determines if the item list headed by Itm and threaded through the
1488 -- Next fields (with null marking the end of the list), contains an
1489 -- entry that uniquely matches the given string. The match is case
1490 -- insensitive and permits unique abbreviation. If the match succeeds,
1491 -- then a pointer to the matching item is returned. Otherwise, an
1492 -- appropriate error message is written. Note that the discriminant
1493 -- of Itm is used to determine the appropriate form of this message.
1494 -- Quiet is normally False as shown, if it is set to True, then no
1495 -- error message is generated in a not found situation (null is still
1496 -- returned to indicate the not-found situation).
1498 function OK_Alphanumerplus (S : String) return Boolean;
1499 -- Checks that S is a string of alphanumeric characters,
1500 -- returning True if all alphanumeric characters,
1501 -- False if empty or a non-alphanumeric character is present.
1503 function OK_Integer (S : String) return Boolean;
1504 -- Checks that S is a string of digits, returning True if all digits,
1505 -- False if empty or a non-digit is present.
1507 procedure Place (C : Character);
1508 -- Place a single character in the buffer, updating Ptr
1510 procedure Place (S : String);
1511 -- Place a string character in the buffer, updating Ptr
1513 procedure Place_Lower (S : String);
1514 -- Place string in buffer, forcing letters to lower case, updating Ptr
1516 procedure Place_Unix_Switches (S : String_Ptr);
1517 -- Given a unix switch string, place corresponding switches in Buffer,
1518 -- updating Ptr appropriatelly. Note that in the case of use of ! the
1519 -- result may be to remove a previously placed switch.
1521 procedure Validate_Command_Or_Option (N : String_Ptr);
1522 -- Check that N is a valid command or option name, i.e. that it is of the
1523 -- form of an Ada identifier with upper case letters and underscores.
1525 procedure Validate_Unix_Switch (S : String_Ptr);
1526 -- Check that S is a valid switch string as described in the syntax for
1527 -- the switch table item UNIX_SWITCH or else begins with a backquote.
1529 ----------------------
1530 -- Init_Object_Dirs --
1531 ----------------------
1533 function Init_Object_Dirs return String_Ptr is
1534 Object_Dirs : Integer;
1535 Object_Dir : array (Integer range 1 .. 256) of String_Access;
1536 Object_Dir_Name : String_Access;
1540 Object_Dir_Name := String_Access (Object_Dir_Default_Name);
1541 Get_Next_Dir_In_Path_Init (Object_Dir_Name);
1545 Dir : String_Access := String_Access
1546 (Get_Next_Dir_In_Path (Object_Dir_Name));
1548 exit when Dir = null;
1549 Object_Dirs := Object_Dirs + 1;
1550 Object_Dir (Object_Dirs)
1551 := String_Access (Normalize_Directory_Name (Dir.all));
1555 for Dirs in 1 .. Object_Dirs loop
1556 Buffer.Increment_Last;
1557 Buffer.Table (Buffer.Last) := '-';
1558 Buffer.Increment_Last;
1559 Buffer.Table (Buffer.Last) := 'L';
1560 Object_Dir_Name := new String'(
1561 To_Canonical_Dir_Spec
1562 (To_Host_Dir_Spec (Object_Dir (Dirs).all, True).all, True).all);
1564 for J in Object_Dir_Name'Range loop
1565 Buffer.Increment_Last;
1566 Buffer.Table (Buffer.Last) := Object_Dir_Name (J);
1569 Buffer.Increment_Last;
1570 Buffer.Table (Buffer.Last) := ' ';
1573 Buffer.Increment_Last;
1574 Buffer.Table (Buffer.Last) := '-';
1575 Buffer.Increment_Last;
1576 Buffer.Table (Buffer.Last) := 'l';
1577 Buffer.Increment_Last;
1578 Buffer.Table (Buffer.Last) := 'g';
1579 Buffer.Increment_Last;
1580 Buffer.Table (Buffer.Last) := 'n';
1581 Buffer.Increment_Last;
1582 Buffer.Table (Buffer.Last) := 'a';
1583 Buffer.Increment_Last;
1584 Buffer.Table (Buffer.Last) := 't';
1586 if Hostparm.OpenVMS then
1587 Buffer.Increment_Last;
1588 Buffer.Table (Buffer.Last) := ' ';
1589 Buffer.Increment_Last;
1590 Buffer.Table (Buffer.Last) := '-';
1591 Buffer.Increment_Last;
1592 Buffer.Table (Buffer.Last) := 'l';
1593 Buffer.Increment_Last;
1594 Buffer.Table (Buffer.Last) := 'd';
1595 Buffer.Increment_Last;
1596 Buffer.Table (Buffer.Last) := 'e';
1597 Buffer.Increment_Last;
1598 Buffer.Table (Buffer.Last) := 'c';
1599 Buffer.Increment_Last;
1600 Buffer.Table (Buffer.Last) := 'g';
1601 Buffer.Increment_Last;
1602 Buffer.Table (Buffer.Last) := 'n';
1603 Buffer.Increment_Last;
1604 Buffer.Table (Buffer.Last) := 'a';
1605 Buffer.Increment_Last;
1606 Buffer.Table (Buffer.Last) := 't';
1609 return new String'(String (Buffer.Table (1 .. Buffer.Last)));
1610 end Init_Object_Dirs;
1616 function Invert_Sense (S : String) return String_Ptr is
1617 Sinv : String (1 .. S'Length * 2);
1618 -- Result (for sure long enough)
1620 Sinvp : Natural := 0;
1621 -- Pointer to output string
1624 for Sp in S'Range loop
1625 if Sp = S'First or else S (Sp - 1) = ',' then
1626 if S (Sp) = '!' then
1629 Sinv (Sinvp + 1) := '!';
1630 Sinv (Sinvp + 2) := S (Sp);
1635 Sinv (Sinvp + 1) := S (Sp);
1640 return new String'(Sinv (1 .. Sinvp));
1643 ----------------------
1644 -- Is_Extensionless --
1645 ----------------------
1647 function Is_Extensionless (F : String) return Boolean is
1649 for J in reverse F'Range loop
1652 elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
1658 end Is_Extensionless;
1664 function Match (S1, S2 : String) return Boolean is
1665 Dif : constant Integer := S2'First - S1'First;
1669 if S1'Length /= S2'Length then
1673 for J in S1'Range loop
1674 if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
1687 function Match_Prefix (S1, S2 : String) return Boolean is
1689 if S1'Length > S2'Length then
1692 return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
1700 function Matching_Name
1703 Quiet : Boolean := False)
1709 -- Little procedure to output command/qualifier/option as appropriate
1710 -- and bump error count.
1718 Errors := Errors + 1;
1723 Put (Standard_Error, "command");
1727 Put (Standard_Error, "qualifier");
1729 Put (Standard_Error, "switch");
1733 Put (Standard_Error, "option");
1737 Put (Standard_Error, "input");
1741 Put (Standard_Error, ": ");
1742 Put (Standard_Error, S);
1746 -- Start of processing for Matching_Name
1749 -- If exact match, that's the one we want
1752 while P1 /= null loop
1753 if Match (S, P1.Name.all) then
1760 -- Now check for prefix matches
1763 while P1 /= null loop
1764 if P1.Name.all = "/<other>" then
1767 elsif not Match_Prefix (S, P1.Name.all) then
1771 -- Here we have found one matching prefix, so see if there is
1772 -- another one (which is an ambiguity)
1775 while P2 /= null loop
1776 if Match_Prefix (S, P2.Name.all) then
1778 Put (Standard_Error, "ambiguous ");
1780 Put (Standard_Error, " (matches ");
1781 Put (Standard_Error, P1.Name.all);
1783 while P2 /= null loop
1784 if Match_Prefix (S, P2.Name.all) then
1785 Put (Standard_Error, ',');
1786 Put (Standard_Error, P2.Name.all);
1792 Put_Line (Standard_Error, ")");
1801 -- If we fall through that loop, then there was only one match
1807 -- If we fall through outer loop, there was no match
1810 Put (Standard_Error, "unrecognized ");
1812 New_Line (Standard_Error);
1818 -----------------------
1819 -- OK_Alphanumerplus --
1820 -----------------------
1822 function OK_Alphanumerplus (S : String) return Boolean is
1824 if S'Length = 0 then
1828 for J in S'Range loop
1829 if not (Is_Alphanumeric (S (J)) or else
1830 S (J) = '_' or else S (J) = '$')
1838 end OK_Alphanumerplus;
1844 function OK_Integer (S : String) return Boolean is
1846 if S'Length = 0 then
1850 for J in S'Range loop
1851 if not Is_Digit (S (J)) then
1864 procedure Place (C : Character) is
1866 Buffer.Increment_Last;
1867 Buffer.Table (Buffer.Last) := C;
1870 procedure Place (S : String) is
1872 for J in S'Range loop
1881 procedure Place_Lower (S : String) is
1883 for J in S'Range loop
1884 Place (To_Lower (S (J)));
1888 -------------------------
1889 -- Place_Unix_Switches --
1890 -------------------------
1892 procedure Place_Unix_Switches (S : String_Ptr) is
1893 P1, P2, P3 : Natural;
1899 while P1 <= S'Last loop
1900 if S (P1) = '!' then
1908 pragma Assert (S (P1) = '-' or else S (P1) = '`');
1910 while P2 < S'Last and then S (P2 + 1) /= ',' loop
1914 -- Switch is now in S (P1 .. P2)
1916 Slen := P2 - P1 + 1;
1920 while P3 <= Buffer.Last - Slen loop
1921 if Buffer.Table (P3) = ' '
1922 and then String (Buffer.Table (P3 + 1 .. P3 + Slen))
1924 and then (P3 + Slen = Buffer.Last
1926 Buffer.Table (P3 + Slen + 1) = ' ')
1928 Buffer.Table (P3 .. Buffer.Last - Slen - 1) :=
1929 Buffer.Table (P3 + Slen + 1 .. Buffer.Last);
1930 Buffer.Set_Last (Buffer.Last - Slen - 1);
1940 if S (P1) = '`' then
1944 Place (S (P1 .. P2));
1949 end Place_Unix_Switches;
1951 --------------------------------
1952 -- Validate_Command_Or_Option --
1953 --------------------------------
1955 procedure Validate_Command_Or_Option (N : String_Ptr) is
1957 pragma Assert (N'Length > 0);
1959 for J in N'Range loop
1961 pragma Assert (N (J - 1) /= '_');
1964 pragma Assert (Is_Upper (N (J)) or else Is_Digit (N (J)));
1968 end Validate_Command_Or_Option;
1970 --------------------------
1971 -- Validate_Unix_Switch --
1972 --------------------------
1974 procedure Validate_Unix_Switch (S : String_Ptr) is
1976 if S (S'First) = '`' then
1980 pragma Assert (S (S'First) = '-' or else S (S'First) = '!');
1982 for J in S'First + 1 .. S'Last loop
1983 pragma Assert (S (J) /= ' ');
1986 pragma Assert (S (J - 1) = ',' and then S (J + 1) = '-');
1990 end Validate_Unix_Switch;
1992 ----------------------
1993 -- List of Commands --
1994 ----------------------
1996 -- Note that we put this after all the local bodies to avoid
1997 -- some access before elaboration problems.
1999 Command_List : array (Natural range <>) of Command_Entry := (
2001 (Cname => new S'("BIND"),
2002 Usage => new S'("GNAT BIND file[.ali] /qualifiers"),
2003 Unixcmd => new S'("gnatbind"),
2004 Switches => Bind_Switches'Access,
2005 Params => new Parameter_Array'(1 => File),
2008 (Cname => new S'("CHOP"),
2009 Usage => new S'("GNAT CHOP file [directory] /qualifiers"),
2010 Unixcmd => new S'("gnatchop"),
2011 Switches => Chop_Switches'Access,
2012 Params => new Parameter_Array'(1 => File, 2 => Optional_File),
2015 (Cname => new S'("COMPILE"),
2016 Usage => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
2017 Unixcmd => new S'("gcc -c -x ada"),
2018 Switches => GCC_Switches'Access,
2019 Params => new Parameter_Array'(1 => Files_Or_Wildcard),
2022 (Cname => new S'("ELIM"),
2023 Usage => new S'("GNAT ELIM name /qualifiers"),
2024 Unixcmd => new S'("gnatelim"),
2025 Switches => Elim_Switches'Access,
2026 Params => new Parameter_Array'(1 => Other_As_Is),
2029 (Cname => new S'("FIND"),
2030 Usage => new S'("GNAT FIND pattern[:sourcefile[:line[:column]]]" &
2031 " filespec[,...] /qualifiers"),
2032 Unixcmd => new S'("gnatfind"),
2033 Switches => Find_Switches'Access,
2034 Params => new Parameter_Array'(1 => Other_As_Is,
2035 2 => Files_Or_Wildcard),
2038 (Cname => new S'("KRUNCH"),
2039 Usage => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
2040 Unixcmd => new S'("gnatkr"),
2041 Switches => Krunch_Switches'Access,
2042 Params => new Parameter_Array'(1 => File),
2045 (Cname => new S'("LIBRARY"),
2046 Usage => new S'("GNAT LIBRARY /[CREATE | SET | DELETE]=directory"
2047 & " [/CONFIG=file]"),
2048 Unixcmd => new S'("gnatlbr"),
2049 Switches => Lbr_Switches'Access,
2050 Params => new Parameter_Array'(1 .. 0 => File),
2053 (Cname => new S'("LINK"),
2054 Usage => new S'("GNAT LINK file[.ali]"
2055 & " [extra obj_&_lib_&_exe_&_opt files]"
2057 Unixcmd => new S'("gnatlink"),
2058 Switches => Link_Switches'Access,
2059 Params => new Parameter_Array'(1 => Unlimited_Files),
2062 (Cname => new S'("LIST"),
2063 Usage => new S'("GNAT LIST /qualifiers object_or_ali_file"),
2064 Unixcmd => new S'("gnatls"),
2065 Switches => List_Switches'Access,
2066 Params => new Parameter_Array'(1 => File),
2069 (Cname => new S'("MAKE"),
2071 new S'("GNAT MAKE file /qualifiers (includes COMPILE /qualifiers)"),
2072 Unixcmd => new S'("gnatmake"),
2073 Switches => Make_Switches'Access,
2074 Params => new Parameter_Array'(1 => File),
2077 (Cname => new S'("PREPROCESS"),
2078 Usage => new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
2079 Unixcmd => new S'("gnatprep"),
2080 Switches => Prep_Switches'Access,
2081 Params => new Parameter_Array'(1 .. 3 => File),
2084 (Cname => new S'("SHARED"),
2085 Usage => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt files]"
2087 Unixcmd => new S'("gcc -shared " & Init_Object_Dirs.all),
2088 Switches => Shared_Switches'Access,
2089 Params => new Parameter_Array'(1 => Unlimited_Files),
2092 (Cname => new S'("STANDARD"),
2093 Usage => new S'("GNAT STANDARD"),
2094 Unixcmd => new S'("gnatpsta"),
2095 Switches => Standard_Switches'Access,
2096 Params => new Parameter_Array'(1 .. 0 => File),
2099 (Cname => new S'("STUB"),
2100 Usage => new S'("GNAT STUB file [directory] /qualifiers"),
2101 Unixcmd => new S'("gnatstub"),
2102 Switches => Stub_Switches'Access,
2103 Params => new Parameter_Array'(1 => File, 2 => Optional_File),
2106 (Cname => new S'("SYSTEM"),
2107 Usage => new S'("GNAT SYSTEM"),
2108 Unixcmd => new S'("gnatpsys"),
2109 Switches => System_Switches'Access,
2110 Params => new Parameter_Array'(1 .. 0 => File),
2113 (Cname => new S'("XREF"),
2114 Usage => new S'("GNAT XREF filespec[,...] /qualifiers"),
2115 Unixcmd => new S'("gnatxref"),
2116 Switches => Xref_Switches'Access,
2117 Params => new Parameter_Array'(1 => Files_Or_Wildcard),
2121 -------------------------------------
2122 -- Start of processing for GNATCmd --
2123 -------------------------------------
2128 -- First we must preprocess the string form of the command and options
2129 -- list into the internal form that we use.
2131 for C in Command_List'Range loop
2134 Command : Item_Ptr := new Command_Item;
2136 Last_Switch : Item_Ptr;
2137 -- Last switch in list
2140 -- Link new command item into list of commands
2142 if Last_Command = null then
2143 Commands := Command;
2145 Last_Command.Next := Command;
2148 Last_Command := Command;
2150 -- Fill in fields of new command item
2152 Command.Name := Command_List (C).Cname;
2153 Command.Usage := Command_List (C).Usage;
2154 Command.Unix_String := Command_List (C).Unixcmd;
2155 Command.Params := Command_List (C).Params;
2156 Command.Defext := Command_List (C).Defext;
2158 Validate_Command_Or_Option (Command.Name);
2160 -- Process the switch list
2162 for S in Command_List (C).Switches'Range loop
2164 SS : constant String_Ptr := Command_List (C).Switches (S);
2166 P : Natural := SS'First;
2167 Sw : Item_Ptr := new Switch_Item;
2169 Last_Opt : Item_Ptr;
2170 -- Pointer to last option
2173 -- Link new switch item into list of switches
2175 if Last_Switch = null then
2176 Command.Switches := Sw;
2178 Last_Switch.Next := Sw;
2183 -- Process switch string, first get name
2185 while SS (P) /= ' ' and SS (P) /= '=' loop
2189 Sw.Name := new String'(SS (SS'First .. P - 1));
2191 -- Direct translation case
2193 if SS (P) = ' ' then
2194 Sw.Translation := T_Direct;
2195 Sw.Unix_String := new String'(SS (P + 1 .. SS'Last));
2196 Validate_Unix_Switch (Sw.Unix_String);
2198 if SS (P - 1) = '>' then
2199 Sw.Translation := T_Other;
2201 elsif SS (P + 1) = '`' then
2204 -- Create the inverted case (/NO ..)
2206 elsif SS (SS'First + 1 .. SS'First + 2) /= "NO" then
2207 Sw := new Switch_Item;
2208 Last_Switch.Next := Sw;
2212 new String'("/NO" & SS (SS'First + 1 .. P - 1));
2213 Sw.Translation := T_Direct;
2214 Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
2215 Validate_Unix_Switch (Sw.Unix_String);
2218 -- Directories translation case
2220 elsif SS (P + 1) = '*' then
2221 pragma Assert (SS (SS'Last) = '*');
2222 Sw.Translation := T_Directories;
2223 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2224 Validate_Unix_Switch (Sw.Unix_String);
2226 -- Directory translation case
2228 elsif SS (P + 1) = '%' then
2229 pragma Assert (SS (SS'Last) = '%');
2230 Sw.Translation := T_Directory;
2231 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2232 Validate_Unix_Switch (Sw.Unix_String);
2234 -- File translation case
2236 elsif SS (P + 1) = '@' then
2237 pragma Assert (SS (SS'Last) = '@');
2238 Sw.Translation := T_File;
2239 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2240 Validate_Unix_Switch (Sw.Unix_String);
2242 -- Numeric translation case
2244 elsif SS (P + 1) = '#' then
2245 pragma Assert (SS (SS'Last) = '#');
2246 Sw.Translation := T_Numeric;
2247 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2248 Validate_Unix_Switch (Sw.Unix_String);
2250 -- Alphanumerplus translation case
2252 elsif SS (P + 1) = '|' then
2253 pragma Assert (SS (SS'Last) = '|');
2254 Sw.Translation := T_Alphanumplus;
2255 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2256 Validate_Unix_Switch (Sw.Unix_String);
2258 -- String translation case
2260 elsif SS (P + 1) = '"' then
2261 pragma Assert (SS (SS'Last) = '"');
2262 Sw.Translation := T_String;
2263 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
2264 Validate_Unix_Switch (Sw.Unix_String);
2266 -- Commands translation case
2268 elsif SS (P + 1) = '?' then
2269 Sw.Translation := T_Commands;
2270 Sw.Unix_String := new String'(SS (P + 2 .. SS'Last));
2272 -- Options translation case
2275 Sw.Translation := T_Options;
2276 Sw.Unix_String := new String'("");
2278 P := P + 1; -- bump past =
2279 while P <= SS'Last loop
2281 Opt : Item_Ptr := new Option_Item;
2285 -- Link new option item into options list
2287 if Last_Opt = null then
2290 Last_Opt.Next := Opt;
2295 -- Fill in fields of new option item
2298 while SS (Q) /= ' ' loop
2302 Opt.Name := new String'(SS (P .. Q - 1));
2303 Validate_Command_Or_Option (Opt.Name);
2308 while Q <= SS'Last and then SS (Q) /= ' ' loop
2312 Opt.Unix_String := new String'(SS (P .. Q - 1));
2313 Validate_Unix_Switch (Opt.Unix_String);
2323 -- If no parameters, give complete list of commands
2325 if Argument_Count = 0 then
2326 Put_Line ("List of available commands");
2329 while Commands /= null loop
2330 Put (Commands.Usage.all);
2332 Put_Line (Commands.Unix_String.all);
2333 Commands := Commands.Next;
2342 exit when Arg_Num > Argument_Count;
2345 Argv : String_Access;
2348 function Get_Arg_End
2352 -- Begins looking at Arg_Idx + 1 and returns the index of the
2353 -- last character before a slash or else the index of the last
2354 -- character in the string Argv.
2356 function Get_Arg_End
2362 for J in Arg_Idx + 1 .. Argv'Last loop
2363 if Argv (J) = '/' then
2372 Argv := new String'(Argument (Arg_Num));
2373 Arg_Idx := Argv'First;
2375 <<Tryagain_After_Coalesce>>
2378 Next_Arg_Idx : Integer;
2379 Arg : String_Access;
2382 Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
2383 Arg := new String'(Argv (Arg_Idx .. Next_Arg_Idx));
2385 -- The first one must be a command name
2387 if Arg_Num = 1 and then Arg_Idx = Argv'First then
2389 Command := Matching_Name (Arg.all, Commands);
2391 if Command = null then
2395 -- Give usage information if only command given
2397 if Argument_Count = 1 and then Next_Arg_Idx = Argv'Last
2399 not (Command.Name.all = "SYSTEM"
2400 or else Command.Name.all = "STANDARD")
2402 Put_Line ("List of available qualifiers and options");
2405 Put (Command.Usage.all);
2407 Put_Line (Command.Unix_String.all);
2410 Sw : Item_Ptr := Command.Switches;
2413 while Sw /= null loop
2417 case Sw.Translation is
2421 Put_Line (Sw.Unix_String.all & "/<other>");
2425 Put_Line (Sw.Unix_String.all);
2427 when T_Directories =>
2428 Put ("=(direc,direc,..direc)");
2430 Put (Sw.Unix_String.all);
2432 Put (Sw.Unix_String.all);
2433 Put_Line (" direc ...");
2438 Put (Sw.Unix_String.all);
2440 if Sw.Unix_String (Sw.Unix_String'Last)
2446 Put_Line ("directory ");
2451 Put (Sw.Unix_String.all);
2453 if Sw.Unix_String (Sw.Unix_String'Last)
2465 if Sw.Unix_String (Sw.Unix_String'First)
2469 (Sw.Unix_String'First + 1
2470 .. Sw.Unix_String'Last));
2472 Put (Sw.Unix_String.all);
2477 when T_Alphanumplus =>
2481 if Sw.Unix_String (Sw.Unix_String'First)
2485 (Sw.Unix_String'First + 1
2486 .. Sw.Unix_String'Last));
2488 Put (Sw.Unix_String.all);
2500 Put (Sw.Unix_String.all);
2502 if Sw.Unix_String (Sw.Unix_String'Last)
2512 Put (" (switches for ");
2513 Put (Sw.Unix_String (
2514 Sw.Unix_String'First + 7
2515 .. Sw.Unix_String'Last));
2518 Put (Sw.Unix_String (
2519 Sw.Unix_String'First
2520 .. Sw.Unix_String'First + 5));
2521 Put_Line (" switches");
2525 Opt : Item_Ptr := Sw.Options;
2528 Put_Line ("=(option,option..)");
2530 while Opt /= null loop
2534 if Opt = Sw.Options then
2539 Put_Line (Opt.Unix_String.all);
2553 Place (Command.Unix_String.all);
2555 -- Special handling for internal debugging switch /?
2557 elsif Arg.all = "/?" then
2558 Display_Command := True;
2560 -- Copy -switch unchanged
2562 elsif Arg (Arg'First) = '-' then
2566 -- Copy quoted switch with quotes stripped
2568 elsif Arg (Arg'First) = '"' then
2569 if Arg (Arg'Last) /= '"' then
2570 Put (Standard_Error, "misquoted argument: ");
2571 Put_Line (Standard_Error, Arg.all);
2572 Errors := Errors + 1;
2575 Put (Arg (Arg'First + 1 .. Arg'Last - 1));
2578 -- Parameter Argument
2580 elsif Arg (Arg'First) /= '/'
2581 and then Make_Commands_Active = null
2583 Param_Count := Param_Count + 1;
2585 if Param_Count <= Command.Params'Length then
2587 case Command.Params (Param_Count) is
2589 when File | Optional_File =>
2591 Normal_File : String_Access
2592 := To_Canonical_File_Spec (Arg.all);
2595 Place_Lower (Normal_File.all);
2597 if Is_Extensionless (Normal_File.all)
2598 and then Command.Defext /= " "
2601 Place (Command.Defext);
2605 when Unlimited_Files =>
2607 Normal_File : String_Access
2608 := To_Canonical_File_Spec (Arg.all);
2610 File_Is_Wild : Boolean := False;
2611 File_List : String_Access_List_Access;
2613 for I in Arg'Range loop
2615 or else Arg (I) = '%'
2617 File_Is_Wild := True;
2621 if File_Is_Wild then
2622 File_List := To_Canonical_File_List
2625 for I in File_List.all'Range loop
2627 Place_Lower (File_List.all (I).all);
2631 Place_Lower (Normal_File.all);
2633 if Is_Extensionless (Normal_File.all)
2634 and then Command.Defext /= " "
2637 Place (Command.Defext);
2641 Param_Count := Param_Count - 1;
2648 when Files_Or_Wildcard =>
2650 -- Remove spaces from a comma separated list
2651 -- of file names and adjust control variables
2654 while Arg_Num < Argument_Count and then
2655 (Argv (Argv'Last) = ',' xor
2656 Argument (Arg_Num + 1)
2657 (Argument (Arg_Num + 1)'First) = ',')
2659 Argv := new String'(Argv.all
2660 & Argument (Arg_Num + 1));
2661 Arg_Num := Arg_Num + 1;
2662 Arg_Idx := Argv'First;
2663 Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
2665 new String'(Argv (Arg_Idx .. Next_Arg_Idx));
2668 -- Parse the comma separated list of VMS filenames
2669 -- and place them on the command line as space
2670 -- separated Unix style filenames. Lower case and
2671 -- add default extension as appropriate.
2674 Arg1_Idx : Integer := Arg'First;
2676 function Get_Arg1_End
2677 (Arg : String; Arg_Idx : Integer)
2679 -- Begins looking at Arg_Idx + 1 and
2680 -- returns the index of the last character
2681 -- before a comma or else the index of the
2682 -- last character in the string Arg.
2684 function Get_Arg1_End
2685 (Arg : String; Arg_Idx : Integer)
2689 for I in Arg_Idx + 1 .. Arg'Last loop
2690 if Arg (I) = ',' then
2701 Next_Arg1_Idx : Integer
2702 := Get_Arg1_End (Arg.all, Arg1_Idx);
2705 := Arg (Arg1_Idx .. Next_Arg1_Idx);
2707 Normal_File : String_Access
2708 := To_Canonical_File_Spec (Arg1);
2712 Place_Lower (Normal_File.all);
2714 if Is_Extensionless (Normal_File.all)
2715 and then Command.Defext /= " "
2718 Place (Command.Defext);
2721 Arg1_Idx := Next_Arg1_Idx + 1;
2724 exit when Arg1_Idx > Arg'Last;
2726 -- Don't allow two or more commas in a row
2728 if Arg (Arg1_Idx) = ',' then
2729 Arg1_Idx := Arg1_Idx + 1;
2730 if Arg1_Idx > Arg'Last or else
2731 Arg (Arg1_Idx) = ','
2733 Put_Line (Standard_Error,
2734 "Malformed Parameter: " & Arg.all);
2735 Put (Standard_Error, "usage: ");
2736 Put_Line (Standard_Error,
2747 -- Qualifier argument
2754 Endp : Natural := 0; -- avoid warning!
2759 while SwP < Arg'Last and then Arg (SwP + 1) /= '=' loop
2763 -- At this point, the switch name is in
2764 -- Arg (Arg'First..SwP) and if that is not the whole
2765 -- switch, then there is an equal sign at
2766 -- Arg (SwP + 1) and the rest of Arg is what comes
2767 -- after the equal sign.
2769 -- If make commands are active, see if we have another
2770 -- COMMANDS_TRANSLATION switch belonging to gnatmake.
2772 if Make_Commands_Active /= null then
2775 (Arg (Arg'First .. SwP),
2779 if Sw /= null and then Sw.Translation = T_Commands then
2785 (Arg (Arg'First .. SwP),
2786 Make_Commands_Active.Switches,
2790 -- For case of GNAT MAKE or CHOP, if we cannot find the
2791 -- switch, then see if it is a recognized compiler switch
2792 -- instead, and if so process the compiler switch.
2794 elsif Command.Name.all = "MAKE"
2795 or else Command.Name.all = "CHOP" then
2798 (Arg (Arg'First .. SwP),
2805 (Arg (Arg'First .. SwP),
2806 Matching_Name ("COMPILE", Commands).Switches,
2810 -- For all other cases, just search the relevant command
2815 (Arg (Arg'First .. SwP),
2821 case Sw.Translation is
2824 Place_Unix_Switches (Sw.Unix_String);
2825 if Arg (SwP + 1) = '=' then
2826 Put (Standard_Error,
2827 "qualifier options ignored: ");
2828 Put_Line (Standard_Error, Arg.all);
2831 when T_Directories =>
2832 if SwP + 1 > Arg'Last then
2833 Put (Standard_Error,
2834 "missing directories for: ");
2835 Put_Line (Standard_Error, Arg.all);
2836 Errors := Errors + 1;
2838 elsif Arg (SwP + 2) /= '(' then
2842 elsif Arg (Arg'Last) /= ')' then
2844 -- Remove spaces from a comma separated list
2845 -- of file names and adjust control
2846 -- variables accordingly.
2848 if Arg_Num < Argument_Count and then
2849 (Argv (Argv'Last) = ',' xor
2850 Argument (Arg_Num + 1)
2851 (Argument (Arg_Num + 1)'First) = ',')
2853 Argv := new String'(Argv.all
2854 & Argument (Arg_Num + 1));
2855 Arg_Num := Arg_Num + 1;
2856 Arg_Idx := Argv'First;
2858 := Get_Arg_End (Argv.all, Arg_Idx);
2860 (Argv (Arg_Idx .. Next_Arg_Idx));
2861 goto Tryagain_After_Coalesce;
2864 Put (Standard_Error,
2865 "incorrectly parenthesized " &
2866 "or malformed argument: ");
2867 Put_Line (Standard_Error, Arg.all);
2868 Errors := Errors + 1;
2872 Endp := Arg'Last - 1;
2875 while SwP <= Endp loop
2877 Dir_Is_Wild : Boolean := False;
2878 Dir_Maybe_Is_Wild : Boolean := False;
2879 Dir_List : String_Access_List_Access;
2884 and then Arg (P2 + 1) /= ','
2887 -- A wildcard directory spec on VMS
2888 -- will contain either * or % or ...
2890 if Arg (P2) = '*' then
2891 Dir_Is_Wild := True;
2893 elsif Arg (P2) = '%' then
2894 Dir_Is_Wild := True;
2896 elsif Dir_Maybe_Is_Wild
2897 and then Arg (P2) = '.'
2898 and then Arg (P2 + 1) = '.'
2900 Dir_Is_Wild := True;
2901 Dir_Maybe_Is_Wild := False;
2903 elsif Dir_Maybe_Is_Wild then
2904 Dir_Maybe_Is_Wild := False;
2906 elsif Arg (P2) = '.'
2907 and then Arg (P2 + 1) = '.'
2909 Dir_Maybe_Is_Wild := True;
2916 if (Dir_Is_Wild) then
2917 Dir_List := To_Canonical_File_List
2918 (Arg (SwP .. P2), True);
2920 for I in Dir_List.all'Range loop
2921 Place_Unix_Switches (Sw.Unix_String);
2922 Place_Lower (Dir_List.all (I).all);
2925 Place_Unix_Switches (Sw.Unix_String);
2926 Place_Lower (To_Canonical_Dir_Spec
2927 (Arg (SwP .. P2), False).all);
2935 if SwP + 1 > Arg'Last then
2936 Put (Standard_Error,
2937 "missing directory for: ");
2938 Put_Line (Standard_Error, Arg.all);
2939 Errors := Errors + 1;
2942 Place_Unix_Switches (Sw.Unix_String);
2944 -- Some switches end in "=". No space here
2947 (Sw.Unix_String'Last) /= '='
2952 Place_Lower (To_Canonical_Dir_Spec
2953 (Arg (SwP + 2 .. Arg'Last), False).all);
2957 if SwP + 1 > Arg'Last then
2958 Put (Standard_Error, "missing file for: ");
2959 Put_Line (Standard_Error, Arg.all);
2960 Errors := Errors + 1;
2963 Place_Unix_Switches (Sw.Unix_String);
2965 -- Some switches end in "=". No space here
2968 (Sw.Unix_String'Last) /= '='
2973 Place_Lower (To_Canonical_File_Spec
2974 (Arg (SwP + 2 .. Arg'Last)).all);
2978 if OK_Integer (Arg (SwP + 2 .. Arg'Last)) then
2979 Place_Unix_Switches (Sw.Unix_String);
2980 Place (Arg (SwP + 2 .. Arg'Last));
2983 Put (Standard_Error, "argument for ");
2984 Put (Standard_Error, Sw.Name.all);
2985 Put_Line (Standard_Error, " must be numeric");
2986 Errors := Errors + 1;
2989 when T_Alphanumplus =>
2991 OK_Alphanumerplus (Arg (SwP + 2 .. Arg'Last))
2993 Place_Unix_Switches (Sw.Unix_String);
2994 Place (Arg (SwP + 2 .. Arg'Last));
2997 Put (Standard_Error, "argument for ");
2998 Put (Standard_Error, Sw.Name.all);
2999 Put_Line (Standard_Error,
3000 " must be alphanumeric");
3001 Errors := Errors + 1;
3006 -- A String value must be extended to the
3007 -- end of the Argv, otherwise strings like
3008 -- "foo/bar" get split at the slash.
3010 -- The begining and ending of the string
3011 -- are flagged with embedded nulls which
3012 -- are removed when building the Spawn
3013 -- call. Nulls are use because they won't
3014 -- show up in a /? output. Quotes aren't
3015 -- used because that would make it difficult
3018 Place_Unix_Switches (Sw.Unix_String);
3019 if Next_Arg_Idx /= Argv'Last then
3020 Next_Arg_Idx := Argv'Last;
3022 (Argv (Arg_Idx .. Next_Arg_Idx));
3025 while SwP < Arg'Last and then
3026 Arg (SwP + 1) /= '=' loop
3031 Place (Arg (SwP + 2 .. Arg'Last));
3036 -- Output -largs/-bargs/-cargs
3039 Place (Sw.Unix_String
3040 (Sw.Unix_String'First ..
3041 Sw.Unix_String'First + 5));
3043 -- Set source of new commands, also setting this
3044 -- non-null indicates that we are in the special
3045 -- commands mode for processing the -xargs case.
3047 Make_Commands_Active :=
3050 (Sw.Unix_String'First + 7 ..
3051 Sw.Unix_String'Last),
3055 if SwP + 1 > Arg'Last then
3056 Place_Unix_Switches (Sw.Options.Unix_String);
3059 elsif Arg (SwP + 2) /= '(' then
3063 elsif Arg (Arg'Last) /= ')' then
3064 Put (Standard_Error,
3065 "incorrectly parenthesized argument: ");
3066 Put_Line (Standard_Error, Arg.all);
3067 Errors := Errors + 1;
3072 Endp := Arg'Last - 1;
3075 while SwP <= Endp loop
3079 and then Arg (P2 + 1) /= ','
3084 -- Option name is in Arg (SwP .. P2)
3086 Opt := Matching_Name (Arg (SwP .. P2),
3090 Place_Unix_Switches (Opt.Unix_String);
3098 (new String'(Sw.Unix_String.all & Arg.all));
3105 Arg_Idx := Next_Arg_Idx + 1;
3108 exit when Arg_Idx > Argv'Last;
3113 Arg_Num := Arg_Num + 1;
3116 if Display_Command then
3117 Put (Standard_Error, "generated command -->");
3118 Put (Standard_Error, String (Buffer.Table (1 .. Buffer.Last)));
3119 Put (Standard_Error, "<--");
3120 New_Line (Standard_Error);
3124 -- Gross error checking that the number of parameters is correct.
3125 -- Not applicable to Unlimited_Files parameters.
3127 if not ((Param_Count = Command.Params'Length - 1 and then
3128 Command.Params (Param_Count + 1) = Unlimited_Files)
3129 or else (Param_Count <= Command.Params'Length))
3131 Put_Line (Standard_Error,
3132 "Parameter count of "
3133 & Integer'Image (Param_Count)
3134 & " not equal to expected "
3135 & Integer'Image (Command.Params'Length));
3136 Put (Standard_Error, "usage: ");
3137 Put_Line (Standard_Error, Command.Usage.all);
3138 Errors := Errors + 1;
3144 -- Prepare arguments for a call to spawn, filtering out
3145 -- embedded nulls place there to delineate strings.
3148 Pname_Ptr : Natural;
3149 Args : Argument_List (1 .. 500);
3152 Exec_Path : String_Access;
3153 Inside_Nul : Boolean := False;
3154 Arg : String (1 .. 1024);
3160 while Pname_Ptr < Buffer.Last
3161 and then Buffer.Table (Pname_Ptr + 1) /= ' '
3163 Pname_Ptr := Pname_Ptr + 1;
3166 P1 := Pname_Ptr + 2;
3168 Arg (Arg_Ctr) := Buffer.Table (P1);
3171 while P1 <= Buffer.Last loop
3173 if Buffer.Table (P1) = ASCII.NUL then
3175 Inside_Nul := False;
3181 if Buffer.Table (P1) = ' ' and then not Inside_Nul then
3183 Arg_Ctr := Arg_Ctr + 1;
3184 Arg (Arg_Ctr) := Buffer.Table (P1);
3190 while P2 < Buffer.Last
3191 and then (Buffer.Table (P2 + 1) /= ' ' or else
3195 Arg_Ctr := Arg_Ctr + 1;
3196 Arg (Arg_Ctr) := Buffer.Table (P2);
3197 if Buffer.Table (P2) = ASCII.NUL then
3198 Arg_Ctr := Arg_Ctr - 1;
3200 Inside_Nul := False;
3207 Args (Nargs) := new String'(String (Arg (1 .. Arg_Ctr)));
3210 Arg (Arg_Ctr) := Buffer.Table (P1);
3214 Exec_Path := Locate_Exec_On_Path
3215 (String (Buffer.Table (1 .. Pname_Ptr)));
3217 if Exec_Path = null then
3218 Put_Line (Standard_Error,
3220 & String (Buffer.Table (1 .. Pname_Ptr)));
3225 := Exit_Status (Spawn (Exec_Path.all, Args (1 .. Nargs)));
3234 Set_Exit_Status (Failure);
3237 Set_Exit_Status (My_Exit_Status);