xref: /csrg-svn/contrib/gcc-2.3.3/gcc.c (revision 60377)
158997Selan /* Compiler driver program that can handle many languages.
258997Selan    Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
358997Selan 
458997Selan This file is part of GNU CC.
558997Selan 
658997Selan GNU CC is free software; you can redistribute it and/or modify
758997Selan it under the terms of the GNU General Public License as published by
858997Selan the Free Software Foundation; either version 2, or (at your option)
958997Selan any later version.
1058997Selan 
1158997Selan GNU CC is distributed in the hope that it will be useful,
1258997Selan but WITHOUT ANY WARRANTY; without even the implied warranty of
1358997Selan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1458997Selan GNU General Public License for more details.
1558997Selan 
1658997Selan You should have received a copy of the GNU General Public License
1758997Selan along with GNU CC; see the file COPYING.  If not, write to
1858997Selan the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
1958997Selan 
2058997Selan This paragraph is here to try to keep Sun CC from dying.
2158997Selan The number of chars here seems crucial!!!!  */
2258997Selan 
2358997Selan /* This program is the user interface to the C compiler and possibly to
2458997Selan other compilers.  It is used because compilation is a complicated procedure
2558997Selan which involves running several programs and passing temporary files between
2658997Selan them, forwarding the users switches to those programs selectively,
2758997Selan and deleting the temporary files at the end.
2858997Selan 
2958997Selan CC recognizes how to compile each input file by suffixes in the file names.
3058997Selan Once it knows which kind of compilation to perform, the procedure for
3158997Selan compilation is specified by a string called a "spec".  */
3258997Selan 
3358997Selan #include <sys/types.h>
3458997Selan #include <ctype.h>
3558997Selan #include <signal.h>
3658997Selan #include <sys/stat.h>
3758997Selan #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
3858997Selan 
3958997Selan #include "config.h"
4058997Selan #include "obstack.h"
4158997Selan #include "gvarargs.h"
4258997Selan #include <stdio.h>
4358997Selan 
4458997Selan #ifndef R_OK
4558997Selan #define R_OK 4
4658997Selan #define W_OK 2
4758997Selan #define X_OK 1
4858997Selan #endif
4958997Selan 
5058997Selan /* Define a generic NULL if one hasn't already been defined.  */
5158997Selan 
5258997Selan #ifndef NULL
5358997Selan #define NULL 0
5458997Selan #endif
5558997Selan 
5658997Selan #ifndef GENERIC_PTR
5758997Selan #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
5858997Selan #define GENERIC_PTR void *
5958997Selan #else
6058997Selan #define GENERIC_PTR char *
6158997Selan #endif
6258997Selan #endif
6358997Selan 
6458997Selan #ifndef NULL_PTR
6558997Selan #define NULL_PTR ((GENERIC_PTR)0)
6658997Selan #endif
6758997Selan 
6858997Selan #ifdef USG
6958997Selan #define vfork fork
7058997Selan #endif /* USG */
7158997Selan 
7258997Selan /* On MSDOS, write temp files in current dir
7358997Selan    because there's no place else we can expect to use.  */
7458997Selan #if __MSDOS__
7558997Selan #ifndef P_tmpdir
7658997Selan #define P_tmpdir "./"
7758997Selan #endif
7858997Selan #endif
7958997Selan 
8058997Selan /* Test if something is a normal file.  */
8158997Selan #ifndef S_ISREG
8258997Selan #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
8358997Selan #endif
8458997Selan 
8558997Selan /* Test if something is a directory.  */
8658997Selan #ifndef S_ISDIR
8758997Selan #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
8858997Selan #endif
8958997Selan 
9058997Selan /* By default there is no special suffix for executables.  */
9158997Selan #ifndef EXECUTABLE_SUFFIX
9258997Selan #define EXECUTABLE_SUFFIX ""
9358997Selan #endif
9458997Selan 
9558997Selan /* By default, colon separates directories in a path.  */
9658997Selan #ifndef PATH_SEPARATOR
9758997Selan #define PATH_SEPARATOR ':'
9858997Selan #endif
9958997Selan 
10058997Selan #define obstack_chunk_alloc xmalloc
10158997Selan #define obstack_chunk_free free
10258997Selan 
10358997Selan extern void free ();
10458997Selan extern char *getenv ();
10558997Selan 
10658997Selan extern int errno, sys_nerr;
107*60377Selan extern const char *const sys_errlist[];
10858997Selan 
10958997Selan extern int execv (), execvp ();
11058997Selan 
11158997Selan /* If a stage of compilation returns an exit status >= 1,
11258997Selan    compilation of that file ceases.  */
11358997Selan 
11458997Selan #define MIN_FATAL_STATUS 1
11558997Selan 
11658997Selan /* Flag saying to print the full filename of libgcc.a
11758997Selan    as found through our usual search mechanism.  */
11858997Selan 
11958997Selan static int print_libgcc_file_name;
12058997Selan 
12158997Selan /* Flag indicating whether we should print the command and arguments */
12258997Selan 
12358997Selan static int verbose_flag;
12458997Selan 
12558997Selan /* Nonzero means write "temp" files in source directory
12658997Selan    and use the source file's name in them, and don't delete them.  */
12758997Selan 
12858997Selan static int save_temps_flag;
12958997Selan 
13058997Selan /* The compiler version specified with -V */
13158997Selan 
13258997Selan static char *spec_version;
13358997Selan 
13458997Selan /* The target machine specified with -b.  */
13558997Selan 
13658997Selan static char *spec_machine = DEFAULT_TARGET_MACHINE;
13758997Selan 
13858997Selan /* Nonzero if cross-compiling.
13958997Selan    When -b is used, the value comes from the `specs' file.  */
14058997Selan 
14158997Selan #ifdef CROSS_COMPILE
14258997Selan static int cross_compile = 1;
14358997Selan #else
14458997Selan static int cross_compile = 0;
14558997Selan #endif
14658997Selan 
14758997Selan /* This is the obstack which we use to allocate many strings.  */
14858997Selan 
14958997Selan static struct obstack obstack;
15058997Selan 
15158997Selan /* This is the obstack to build an environment variable to pass to
15258997Selan    collect2 that describes all of the relevant switches of what to
15358997Selan    pass the compiler in building the list of pointers to constructors
15458997Selan    and destructors.  */
15558997Selan 
15658997Selan static struct obstack collect_obstack;
15758997Selan 
15858997Selan extern char *version_string;
15958997Selan 
16058997Selan static void set_spec ();
16158997Selan static struct compiler *lookup_compiler ();
16258997Selan static char *find_a_file ();
16358997Selan static void add_prefix ();
16458997Selan static char *skip_whitespace ();
16558997Selan static void record_temp_file ();
16658997Selan static char *handle_braces ();
16758997Selan static char *save_string ();
16858997Selan static char *concat ();
16958997Selan static int do_spec ();
17058997Selan static int do_spec_1 ();
17158997Selan static char *find_file ();
17258997Selan static int is_linker_dir ();
17358997Selan static void validate_switches ();
17458997Selan static void validate_all_switches ();
17558997Selan static void give_switch ();
17658997Selan static void pfatal_with_name ();
17758997Selan static void perror_with_name ();
17858997Selan static void perror_exec ();
17958997Selan static void fatal ();
18058997Selan static void error ();
18158997Selan void fancy_abort ();
18258997Selan char *xmalloc ();
18358997Selan char *xrealloc ();
18458997Selan 
18558997Selan /* Specs are strings containing lines, each of which (if not blank)
18658997Selan is made up of a program name, and arguments separated by spaces.
18758997Selan The program name must be exact and start from root, since no path
18858997Selan is searched and it is unreliable to depend on the current working directory.
18958997Selan Redirection of input or output is not supported; the subprograms must
19058997Selan accept filenames saying what files to read and write.
19158997Selan 
19258997Selan In addition, the specs can contain %-sequences to substitute variable text
19358997Selan or for conditional text.  Here is a table of all defined %-sequences.
19458997Selan Note that spaces are not generated automatically around the results of
19558997Selan expanding these sequences; therefore, you can concatenate them together
19658997Selan or with constant text in a single argument.
19758997Selan 
19858997Selan  %%	substitute one % into the program name or argument.
19958997Selan  %i     substitute the name of the input file being processed.
20058997Selan  %b     substitute the basename of the input file being processed.
20158997Selan 	This is the substring up to (and not including) the last period
20258997Selan 	and not including the directory.
20358997Selan  %g     substitute the temporary-file-name-base.  This is a string chosen
20458997Selan 	once per compilation.  Different temporary file names are made by
20558997Selan 	concatenation of constant strings on the end, as in `%g.s'.
20658997Selan 	%g also has the same effect of %d.
20758997Selan  %u	like %g, but make the temporary file name unique.
20858997Selan  %U	returns the last file name generated with %u.
20958997Selan  %d	marks the argument containing or following the %d as a
21058997Selan 	temporary file name, so that that file will be deleted if CC exits
21158997Selan 	successfully.  Unlike %g, this contributes no text to the argument.
21258997Selan  %w	marks the argument containing or following the %w as the
21358997Selan 	"output file" of this compilation.  This puts the argument
21458997Selan 	into the sequence of arguments that %o will substitute later.
21558997Selan  %W{...}
21658997Selan 	like %{...} but mark last argument supplied within
21758997Selan 	as a file to be deleted on failure.
21858997Selan  %o	substitutes the names of all the output files, with spaces
21958997Selan 	automatically placed around them.  You should write spaces
22058997Selan 	around the %o as well or the results are undefined.
22158997Selan 	%o is for use in the specs for running the linker.
22258997Selan 	Input files whose names have no recognized suffix are not compiled
22358997Selan 	at all, but they are included among the output files, so they will
22458997Selan 	be linked.
22558997Selan  %p	substitutes the standard macro predefinitions for the
22658997Selan 	current target machine.  Use this when running cpp.
22758997Selan  %P	like %p, but puts `__' before and after the name of each macro.
22858997Selan 	(Except macros that already have __.)
22958997Selan 	This is for ANSI C.
23058997Selan  %I	Substitute a -iprefix option made from GCC_EXEC_PREFIX.
23158997Selan  %s     current argument is the name of a library or startup file of some sort.
23258997Selan         Search for that file in a standard list of directories
23358997Selan 	and substitute the full name found.
23458997Selan  %eSTR  Print STR as an error message.  STR is terminated by a newline.
23558997Selan         Use this when inconsistent options are detected.
23658997Selan  %x{OPTION}	Accumulate an option for %X.
23758997Selan  %X	Output the accumulated linker options specified by compilations.
23858997Selan  %Y	Output the accumulated assembler options specified by compilations.
23958997Selan  %a     process ASM_SPEC as a spec.
24058997Selan         This allows config.h to specify part of the spec for running as.
24158997Selan  %A	process ASM_FINAL_SPEC as a spec.  A capital A is actually
24258997Selan 	used here.  This can be used to run a post-processor after the
24358997Selan 	assembler has done it's job.
24458997Selan  %D	Dump out a -L option for each directory in library_prefix,
24558997Selan 	followed by a -L option for each directory in startfile_prefix.
24658997Selan  %l     process LINK_SPEC as a spec.
24758997Selan  %L     process LIB_SPEC as a spec.
24858997Selan  %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
24958997Selan  %E     process ENDFILE_SPEC as a spec.  A capital E is actually used here.
25058997Selan  %c	process SIGNED_CHAR_SPEC as a spec.
25158997Selan  %C     process CPP_SPEC as a spec.  A capital C is actually used here.
25258997Selan  %1	process CC1_SPEC as a spec.
25358997Selan  %2	process CC1PLUS_SPEC as a spec.
25458997Selan  %*	substitute the variable part of a matched option.  (See below.)
25558997Selan 	Note that each comma in the substituted string is replaced by
25658997Selan 	a single space.
25758997Selan  %{S}   substitutes the -S switch, if that switch was given to CC.
25858997Selan 	If that switch was not specified, this substitutes nothing.
25958997Selan 	Here S is a metasyntactic variable.
26058997Selan  %{S*}  substitutes all the switches specified to CC whose names start
26158997Selan 	with -S.  This is used for -o, -D, -I, etc; switches that take
26258997Selan 	arguments.  CC considers `-o foo' as being one switch whose
26358997Selan 	name starts with `o'.  %{o*} would substitute this text,
26458997Selan 	including the space; thus, two arguments would be generated.
26558997Selan  %{S*:X} substitutes X if one or more switches whose names start with -S are
26658997Selan 	specified to CC.  Note that the tail part of the -S option
26758997Selan 	(i.e. the part matched by the `*') will be substituted for each
26858997Selan 	occurrence of %* within X.
26958997Selan  %{S:X} substitutes X, but only if the -S switch was given to CC.
27058997Selan  %{!S:X} substitutes X, but only if the -S switch was NOT given to CC.
27158997Selan  %{|S:X} like %{S:X}, but if no S switch, substitute `-'.
27258997Selan  %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
27358997Selan  %{.S:X} substitutes X, but only if processing a file with suffix S.
27458997Selan  %{!.S:X} substitutes X, but only if NOT processing a file with suffix S.
27558997Selan  %(Spec) processes a specification defined in a specs file as *Spec:
27658997Selan  %[Spec] as above, but put __ around -D arguments
27758997Selan 
27858997Selan The conditional text X in a %{S:X} or %{!S:X} construct may contain
27958997Selan other nested % constructs or spaces, or even newlines.  They are
28058997Selan processed as usual, as described above.
28158997Selan 
28258997Selan The character | is used to indicate that a command should be piped to
28358997Selan the following command, but only if -pipe is specified.
28458997Selan 
28558997Selan Note that it is built into CC which switches take arguments and which
28658997Selan do not.  You might think it would be useful to generalize this to
28758997Selan allow each compiler's spec to say which switches take arguments.  But
28858997Selan this cannot be done in a consistent fashion.  CC cannot even decide
28958997Selan which input files have been specified without knowing which switches
29058997Selan take arguments, and it must know which input files to compile in order
29158997Selan to tell which compilers to run.
29258997Selan 
29358997Selan CC also knows implicitly that arguments starting in `-l' are to be
29458997Selan treated as compiler output files, and passed to the linker in their
29558997Selan proper position among the other output files.  */
29658997Selan 
29758997Selan /* Define the macros used for specs %a, %l, %L, %S, %c, %C, %1.  */
29858997Selan 
29958997Selan /* config.h can define ASM_SPEC to provide extra args to the assembler
30058997Selan    or extra switch-translations.  */
30158997Selan #ifndef ASM_SPEC
30258997Selan #define ASM_SPEC ""
30358997Selan #endif
30458997Selan 
30558997Selan /* config.h can define ASM_FINAL_SPEC to run a post processor after
30658997Selan    the assembler has run.  */
30758997Selan #ifndef ASM_FINAL_SPEC
30858997Selan #define ASM_FINAL_SPEC ""
30958997Selan #endif
31058997Selan 
31158997Selan /* config.h can define CPP_SPEC to provide extra args to the C preprocessor
31258997Selan    or extra switch-translations.  */
31358997Selan #ifndef CPP_SPEC
31458997Selan #define CPP_SPEC ""
31558997Selan #endif
31658997Selan 
31758997Selan /* config.h can define CC1_SPEC to provide extra args to cc1 and cc1plus
31858997Selan    or extra switch-translations.  */
31958997Selan #ifndef CC1_SPEC
32058997Selan #define CC1_SPEC ""
32158997Selan #endif
32258997Selan 
32358997Selan /* config.h can define CC1PLUS_SPEC to provide extra args to cc1plus
32458997Selan    or extra switch-translations.  */
32558997Selan #ifndef CC1PLUS_SPEC
32658997Selan #define CC1PLUS_SPEC ""
32758997Selan #endif
32858997Selan 
32958997Selan /* config.h can define LINK_SPEC to provide extra args to the linker
33058997Selan    or extra switch-translations.  */
33158997Selan #ifndef LINK_SPEC
33258997Selan #define LINK_SPEC ""
33358997Selan #endif
33458997Selan 
33558997Selan /* config.h can define LIB_SPEC to override the default libraries.  */
33658997Selan #ifndef LIB_SPEC
33758997Selan #define LIB_SPEC "%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
33858997Selan #endif
33958997Selan 
34058997Selan /* config.h can define STARTFILE_SPEC to override the default crt0 files.  */
34158997Selan #ifndef STARTFILE_SPEC
34258997Selan #define STARTFILE_SPEC  \
34358997Selan   "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}"
34458997Selan #endif
34558997Selan 
34658997Selan /* config.h can define SWITCHES_NEED_SPACES to control passing -o and -L.
34758997Selan    Make the string nonempty to require spaces there.  */
34858997Selan #ifndef SWITCHES_NEED_SPACES
34958997Selan #define SWITCHES_NEED_SPACES ""
35058997Selan #endif
35158997Selan 
35258997Selan /* config.h can define ENDFILE_SPEC to override the default crtn files.  */
35358997Selan #ifndef ENDFILE_SPEC
35458997Selan #define ENDFILE_SPEC ""
35558997Selan #endif
35658997Selan 
35758997Selan /* This spec is used for telling cpp whether char is signed or not.  */
35858997Selan #ifndef SIGNED_CHAR_SPEC
35958997Selan /* Use #if rather than ?:
36058997Selan    because MIPS C compiler rejects like ?: in initializers.  */
36158997Selan #if DEFAULT_SIGNED_CHAR
36258997Selan #define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
36358997Selan #else
36458997Selan #define SIGNED_CHAR_SPEC "%{!fsigned-char:-D__CHAR_UNSIGNED__}"
36558997Selan #endif
36658997Selan #endif
36758997Selan 
36858997Selan static char *cpp_spec = CPP_SPEC;
36958997Selan static char *cpp_predefines = CPP_PREDEFINES;
37058997Selan static char *cc1_spec = CC1_SPEC;
37158997Selan static char *cc1plus_spec = CC1PLUS_SPEC;
37258997Selan static char *signed_char_spec = SIGNED_CHAR_SPEC;
37358997Selan static char *asm_spec = ASM_SPEC;
37458997Selan static char *asm_final_spec = ASM_FINAL_SPEC;
37558997Selan static char *link_spec = LINK_SPEC;
37658997Selan static char *lib_spec = LIB_SPEC;
37758997Selan static char *endfile_spec = ENDFILE_SPEC;
37858997Selan static char *startfile_spec = STARTFILE_SPEC;
37958997Selan static char *switches_need_spaces = SWITCHES_NEED_SPACES;
38058997Selan 
38158997Selan /* This defines which switch letters take arguments.  */
38258997Selan 
38358997Selan #ifndef SWITCH_TAKES_ARG
38458997Selan #define SWITCH_TAKES_ARG(CHAR)      \
38558997Selan   ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
38658997Selan    || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
38758997Selan    || (CHAR) == 'I' || (CHAR) == 'm' \
38858997Selan    || (CHAR) == 'L' || (CHAR) == 'A')
38958997Selan #endif
39058997Selan 
39158997Selan /* This defines which multi-letter switches take arguments.  */
39258997Selan 
39358997Selan #ifndef WORD_SWITCH_TAKES_ARG
39458997Selan #define WORD_SWITCH_TAKES_ARG(STR)			\
39558997Selan  (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")	\
39658997Selan   || !strcmp (STR, "Tbss") || !strcmp (STR, "include")	\
39758997Selan   || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info"))
39858997Selan #endif
39958997Selan 
40058997Selan /* Record the mapping from file suffixes for compilation specs.  */
40158997Selan 
40258997Selan struct compiler
40358997Selan {
40458997Selan   char *suffix;			/* Use this compiler for input files
40558997Selan 				   whose names end in this suffix.  */
40658997Selan 
40758997Selan   char *spec[4];		/* To use this compiler, concatenate these
40858997Selan 				   specs and pass to do_spec.  */
40958997Selan };
41058997Selan 
41158997Selan /* Pointer to a vector of `struct compiler' that gives the spec for
41258997Selan    compiling a file, based on its suffix.
41358997Selan    A file that does not end in any of these suffixes will be passed
41458997Selan    unchanged to the loader and nothing else will be done to it.
41558997Selan 
41658997Selan    An entry containing two 0s is used to terminate the vector.
41758997Selan 
41858997Selan    If multiple entries match a file, the last matching one is used.  */
41958997Selan 
42058997Selan static struct compiler *compilers;
42158997Selan 
42258997Selan /* Number of entries in `compilers', not counting the null terminator.  */
42358997Selan 
42458997Selan static int n_compilers;
42558997Selan 
42658997Selan /* The default list of file name suffixes and their compilation specs.  */
42758997Selan 
42858997Selan static struct compiler default_compilers[] =
42958997Selan {
43058997Selan   {".c", "@c"},
43158997Selan   {"@c",
43258997Selan    "cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
43358997Selan 	%{C:%{!E:%eGNU C does not support -C without using -E}}\
43458997Selan 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
43558997Selan         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
43658997Selan 	%{!undef:%{!ansi:%p} %P} %{trigraphs} \
43758997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
43858997Selan         %{traditional-cpp:-traditional}\
43958997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
44058997Selan         %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
44158997Selan    "%{!M:%{!MM:%{!E:cc1 %{!pipe:%g.i} %1 \
44258997Selan 		   %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
44358997Selan 		   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
44458997Selan 		   %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
44558997Selan 		   %{aux-info*}\
44658997Selan 		   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
44758997Selan 		   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
44858997Selan               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
44958997Selan 		      %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
45058997Selan                       %{!pipe:%g.s} %A\n }}}}"},
45158997Selan   {"-",
45258997Selan    "%{E:cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
45358997Selan 	%{C:%{!E:%eGNU C does not support -C without using -E}}\
45458997Selan 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
45558997Selan         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
45658997Selan 	%{!undef:%{!ansi:%p} %P} %{trigraphs}\
45758997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
45858997Selan         %{traditional-cpp:-traditional}\
45958997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
46058997Selan         %i %W{o*}}\
46158997Selan     %{!E:%e-E required when input is from standard input}"},
46258997Selan   {".m", "@objective-c"},
46358997Selan   {"@objective-c",
46458997Selan    "cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
46558997Selan 	%{C:%{!E:%eGNU C does not support -C without using -E}}\
46658997Selan 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d}\
46758997Selan         -undef -D__OBJC__ -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
46858997Selan 	%{!undef:%{!ansi:%p} %P} %{trigraphs}\
46958997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
47058997Selan         %{traditional-cpp:-traditional}\
47158997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
47258997Selan         %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
47358997Selan    "%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
47458997Selan 		   %{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a}\
47558997Selan 		   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
47658997Selan 		   %{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
47758997Selan     		   -lang-objc %{gen-decls} \
47858997Selan 		   %{aux-info*}\
47958997Selan 		   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
48058997Selan 		   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
48158997Selan               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
48258997Selan 		      %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
48358997Selan                       %{!pipe:%g.s} %A\n }}}}"},
48458997Selan   {".h", "@c-header"},
48558997Selan   {"@c-header",
48658997Selan    "%{!E:%eCompilation of header file requested} \
48758997Selan     cpp %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
48858997Selan 	%{C:%{!E:%eGNU C does not support -C without using -E}}\
48958997Selan 	 %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
49058997Selan         -undef -D__GNUC__=2 %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
49158997Selan 	%{!undef:%{!ansi:%p} %P} %{trigraphs}\
49258997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
49358997Selan         %{traditional-cpp:-traditional}\
49458997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
49558997Selan         %i %W{o*}"},
49658997Selan   {".cc", "@c++"},
49758997Selan   {".cxx", "@c++"},
49858997Selan   {".C", "@c++"},
49958997Selan   {"@c++",
50058997Selan    "cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
50158997Selan 	%{C:%{!E:%eGNU C++ does not support -C without using -E}}\
50258997Selan 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} \
50358997Selan 	-undef -D__GNUC__=2 -D__GNUG__=2 -D__cplusplus \
50458997Selan 	%{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
50558997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
50658997Selan         %{traditional-cpp:-traditional} %{trigraphs}\
50758997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
50858997Selan         %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
50958997Selan    "%{!M:%{!MM:%{!E:cc1plus %{!pipe:%g.i} %1 %2\
51058997Selan 		   %{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
51158997Selan 		   %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
51258997Selan 		   %{v:-version} %{pg:-p} %{p} %{f*} %{+e*}\
51358997Selan 		   %{aux-info*}\
51458997Selan 		   %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
51558997Selan 		   %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
51658997Selan               %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
51758997Selan 		      %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
51858997Selan                       %{!pipe:%g.s} %A\n }}}}"},
51958997Selan   {".i", "@cpp-output"},
52058997Selan   {"@cpp-output",
52158997Selan    "cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a}\
52258997Selan 	%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
52358997Selan 	%{v:-version} %{pg:-p} %{p} %{f*}\
52458997Selan 	%{aux-info*}\
52558997Selan 	%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
52658997Selan 	%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
52758997Selan     %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
52858997Selan             %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o} %{!pipe:%g.s} %A\n }"},
52958997Selan   {".ii", "@c++-cpp-output"},
53058997Selan   {"@c++-cpp-output",
53158997Selan    "cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
53258997Selan 	    %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} %{traditional}\
53358997Selan 	    %{v:-version} %{pg:-p} %{p} %{f*} %{+e*}\
53458997Selan 	    %{aux-info*}\
53558997Selan 	    %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
53658997Selan 	    %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
53758997Selan        %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
53858997Selan 	       %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
53958997Selan 	       %{!pipe:%g.s} %A\n }"},
54058997Selan   {".s", "@assembler"},
54158997Selan   {"@assembler",
54258997Selan    "%{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
54358997Selan             %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o} %i %A\n }"},
54458997Selan   {".S", "@assembler-with-cpp"},
54558997Selan   {"@assembler-with-cpp",
54658997Selan    "cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
54758997Selan 	%{C:%{!E:%eGNU C does not support -C without using -E}}\
54858997Selan 	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{trigraphs} \
54958997Selan         -undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
55058997Selan         %c %{O*:-D__OPTIMIZE__} %{traditional} %{ftraditional:-traditional}\
55158997Selan         %{traditional-cpp:-traditional}\
55258997Selan 	%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
55358997Selan         %i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
55458997Selan    "%{!M:%{!MM:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
55558997Selan                     %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
55658997Selan 		    %{!pipe:%g.s} %A\n }}}}"},
55758997Selan   /* Mark end of table */
55858997Selan   {0, 0}
55958997Selan };
56058997Selan 
56158997Selan /* Number of elements in default_compilers, not counting the terminator.  */
56258997Selan 
56358997Selan static int n_default_compilers
56458997Selan   = (sizeof default_compilers / sizeof (struct compiler)) - 1;
56558997Selan 
56658997Selan /* Here is the spec for running the linker, after compiling all files.  */
56758997Selan 
56858997Selan /* -u* was put back because both BSD and SysV seem to support it.  */
56958997Selan /* %{static:} simply prevents an error message if the target machine
57058997Selan    doesn't handle -static.  */
57158997Selan #ifdef LINK_LIBGCC_SPECIAL_1
57258997Selan /* Have gcc do the search for libgcc.a, but generate -L options as usual.  */
57358997Selan static char *link_command_spec = "\
57458997Selan %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
57558997Selan 			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
57658997Selan 			%{!A:%{!nostdlib:%S}} %{static:}\
577*60377Selan 			%{L*} %D %o %{!nostdlib:%L libgcc.a%s %L %{!A:%E}}\n }}}}}";
57858997Selan #else
57958997Selan #ifdef LINK_LIBGCC_SPECIAL
58058997Selan /* Have gcc do the search for libgcc.a, and don't generate -L options.  */
58158997Selan static char *link_command_spec = "\
58258997Selan %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
58358997Selan 			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
58458997Selan 			%{!A:%{!nostdlib:%S}} %{static:}\
585*60377Selan 			%{L*} %o %{!nostdlib:%L libgcc.a%s %L %{!A:%E}}\n }}}}}";
58658997Selan #else
58758997Selan /* Use -L and have the linker do the search for -lgcc.  */
58858997Selan static char *link_command_spec = "\
58958997Selan %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
59058997Selan 			%{r} %{s} %{T*} %{t} %{u*} %{x} %{z}\
59158997Selan 			%{!A:%{!nostdlib:%S}} %{static:}\
592*60377Selan 			%{L*} %D %o %{!nostdlib:%L -lgcc %L %{!A:%E}}\n }}}}}";
59358997Selan #endif
59458997Selan #endif
59558997Selan 
59658997Selan /* A vector of options to give to the linker.
59758997Selan    These options are accumulated by -Xlinker and -Wl,
59858997Selan    and substituted into the linker command with %X.  */
59958997Selan static int n_linker_options;
60058997Selan static char **linker_options;
60158997Selan 
60258997Selan /* A vector of options to give to the assembler.
60358997Selan    These options are accumulated by -Wa,
60458997Selan    and substituted into the assembler command with %X.  */
60558997Selan static int n_assembler_options;
60658997Selan static char **assembler_options;
60758997Selan 
60858997Selan /* Read compilation specs from a file named FILENAME,
60958997Selan    replacing the default ones.
61058997Selan 
61158997Selan    A suffix which starts with `*' is a definition for
61258997Selan    one of the machine-specific sub-specs.  The "suffix" should be
61358997Selan    *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
61458997Selan    The corresponding spec is stored in asm_spec, etc.,
61558997Selan    rather than in the `compilers' vector.
61658997Selan 
61758997Selan    Anything invalid in the file is a fatal error.  */
61858997Selan 
61958997Selan static void
read_specs(filename)62058997Selan read_specs (filename)
62158997Selan      char *filename;
62258997Selan {
62358997Selan   int desc;
62458997Selan   struct stat statbuf;
62558997Selan   char *buffer;
62658997Selan   register char *p;
62758997Selan 
62858997Selan   if (verbose_flag)
62958997Selan     fprintf (stderr, "Reading specs from %s\n", filename);
63058997Selan 
63158997Selan   /* Open and stat the file.  */
63258997Selan   desc = open (filename, 0, 0);
63358997Selan   if (desc < 0)
63458997Selan     pfatal_with_name (filename);
63558997Selan   if (stat (filename, &statbuf) < 0)
63658997Selan     pfatal_with_name (filename);
63758997Selan 
63858997Selan   /* Read contents of file into BUFFER.  */
63958997Selan   buffer = xmalloc ((unsigned) statbuf.st_size + 1);
64058997Selan   read (desc, buffer, (unsigned) statbuf.st_size);
64158997Selan   buffer[statbuf.st_size] = 0;
64258997Selan   close (desc);
64358997Selan 
64458997Selan   /* Scan BUFFER for specs, putting them in the vector.  */
64558997Selan   p = buffer;
64658997Selan   while (1)
64758997Selan     {
64858997Selan       char *suffix;
64958997Selan       char *spec;
65058997Selan       char *in, *out, *p1, *p2;
65158997Selan 
65258997Selan       /* Advance P in BUFFER to the next nonblank nocomment line.  */
65358997Selan       p = skip_whitespace (p);
65458997Selan       if (*p == 0)
65558997Selan 	break;
65658997Selan 
65758997Selan       /* Find the colon that should end the suffix.  */
65858997Selan       p1 = p;
65958997Selan       while (*p1 && *p1 != ':' && *p1 != '\n') p1++;
66058997Selan       /* The colon shouldn't be missing.  */
66158997Selan       if (*p1 != ':')
66258997Selan 	fatal ("specs file malformed after %d characters", p1 - buffer);
66358997Selan       /* Skip back over trailing whitespace.  */
66458997Selan       p2 = p1;
66558997Selan       while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t')) p2--;
66658997Selan       /* Copy the suffix to a string.  */
66758997Selan       suffix = save_string (p, p2 - p);
66858997Selan       /* Find the next line.  */
66958997Selan       p = skip_whitespace (p1 + 1);
67058997Selan       if (p[1] == 0)
67158997Selan 	fatal ("specs file malformed after %d characters", p - buffer);
67258997Selan       p1 = p;
67358997Selan       /* Find next blank line.  */
67458997Selan       while (*p1 && !(*p1 == '\n' && p1[1] == '\n')) p1++;
67558997Selan       /* Specs end at the blank line and do not include the newline.  */
67658997Selan       spec = save_string (p, p1 - p);
67758997Selan       p = p1;
67858997Selan 
67958997Selan       /* Delete backslash-newline sequences from the spec.  */
68058997Selan       in = spec;
68158997Selan       out = spec;
68258997Selan       while (*in != 0)
68358997Selan 	{
68458997Selan 	  if (in[0] == '\\' && in[1] == '\n')
68558997Selan 	    in += 2;
68658997Selan 	  else if (in[0] == '#')
68758997Selan 	    {
68858997Selan 	      while (*in && *in != '\n') in++;
68958997Selan 	    }
69058997Selan 	  else
69158997Selan 	    *out++ = *in++;
69258997Selan 	}
69358997Selan       *out = 0;
69458997Selan 
69558997Selan       if (suffix[0] == '*')
69658997Selan 	{
69758997Selan 	  if (! strcmp (suffix, "*link_command"))
69858997Selan 	    link_command_spec = spec;
69958997Selan 	  else
70058997Selan 	    set_spec (suffix + 1, spec);
70158997Selan 	}
70258997Selan       else
70358997Selan 	{
70458997Selan 	  /* Add this pair to the vector.  */
70558997Selan 	  compilers
70658997Selan 	    = ((struct compiler *)
70758997Selan 	       xrealloc (compilers, (n_compilers + 2) * sizeof (struct compiler)));
70858997Selan 	  compilers[n_compilers].suffix = suffix;
70958997Selan 	  bzero (compilers[n_compilers].spec,
71058997Selan 		 sizeof compilers[n_compilers].spec);
71158997Selan 	  compilers[n_compilers].spec[0] = spec;
71258997Selan 	  n_compilers++;
71358997Selan 	}
71458997Selan 
71558997Selan       if (*suffix == 0)
71658997Selan 	link_command_spec = spec;
71758997Selan     }
71858997Selan 
71958997Selan   if (link_command_spec == 0)
72058997Selan     fatal ("spec file has no spec for linking");
72158997Selan }
72258997Selan 
72358997Selan static char *
skip_whitespace(p)72458997Selan skip_whitespace (p)
72558997Selan      char *p;
72658997Selan {
72758997Selan   while (1)
72858997Selan     {
72958997Selan       /* A fully-blank line is a delimiter in the SPEC file and shouldn't
73058997Selan 	 be considered whitespace.  */
73158997Selan       if (p[0] == '\n' && p[1] == '\n' && p[2] == '\n')
73258997Selan 	return p + 1;
73358997Selan       else if (*p == '\n' || *p == ' ' || *p == '\t')
73458997Selan 	p++;
73558997Selan       else if (*p == '#')
73658997Selan 	{
73758997Selan 	  while (*p != '\n') p++;
73858997Selan 	  p++;
73958997Selan 	}
74058997Selan       else
74158997Selan 	break;
74258997Selan     }
74358997Selan 
74458997Selan   return p;
74558997Selan }
74658997Selan 
74758997Selan /* Structure to keep track of the specs that have been defined so far.  These
74858997Selan    are accessed using %(specname) or %[specname] in a compiler or link spec. */
74958997Selan 
75058997Selan struct spec_list
75158997Selan {
75258997Selan   char *name;                 /* Name of the spec. */
75358997Selan   char *spec;                 /* The spec itself. */
75458997Selan   struct spec_list *next;     /* Next spec in linked list. */
75558997Selan };
75658997Selan 
75758997Selan /* List of specs that have been defined so far. */
75858997Selan 
75958997Selan static struct spec_list *specs = (struct spec_list *) 0;
76058997Selan 
76158997Selan /* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
76258997Selan    removed; If the spec starts with a + then SPEC is added to the end of the
76358997Selan    current spec. */
76458997Selan 
76558997Selan static void
set_spec(name,spec)76658997Selan set_spec (name, spec)
76758997Selan      char *name;
76858997Selan      char *spec;
76958997Selan {
77058997Selan   struct spec_list *sl;
77158997Selan   char *old_spec;
77258997Selan 
77358997Selan   /* See if the spec already exists */
77458997Selan   for (sl = specs; sl; sl = sl->next)
77558997Selan     if (strcmp (sl->name, name) == 0)
77658997Selan       break;
77758997Selan 
77858997Selan   if (!sl)
77958997Selan     {
78058997Selan       /* Not found - make it */
78158997Selan       sl = (struct spec_list *) xmalloc (sizeof (struct spec_list));
78258997Selan       sl->name = save_string (name, strlen (name));
78358997Selan       sl->spec = save_string ("", 0);
78458997Selan       sl->next = specs;
78558997Selan       specs = sl;
78658997Selan     }
78758997Selan 
78858997Selan   old_spec = sl->spec;
78958997Selan   if (name && spec[0] == '+' && isspace (spec[1]))
79058997Selan     sl->spec = concat (old_spec, spec + 1, "");
79158997Selan   else
79258997Selan     sl->spec = save_string (spec, strlen (spec));
79358997Selan 
79458997Selan   if (! strcmp (name, "asm"))
79558997Selan     asm_spec = sl->spec;
79658997Selan   else if (! strcmp (name, "asm_final"))
79758997Selan     asm_final_spec = sl->spec;
79858997Selan   else if (! strcmp (name, "cc1"))
79958997Selan     cc1_spec = sl->spec;
80058997Selan   else if (! strcmp (name, "cc1plus"))
80158997Selan     cc1plus_spec = sl->spec;
80258997Selan   else if (! strcmp (name, "cpp"))
80358997Selan     cpp_spec = sl->spec;
80458997Selan   else if (! strcmp (name, "endfile"))
80558997Selan     endfile_spec = sl->spec;
80658997Selan   else if (! strcmp (name, "lib"))
80758997Selan     lib_spec = sl->spec;
80858997Selan   else if (! strcmp (name, "link"))
80958997Selan     link_spec = sl->spec;
81058997Selan   else if (! strcmp (name, "predefines"))
81158997Selan     cpp_predefines = sl->spec;
81258997Selan   else if (! strcmp (name, "signed_char"))
81358997Selan     signed_char_spec = sl->spec;
81458997Selan   else if (! strcmp (name, "startfile"))
81558997Selan     startfile_spec = sl->spec;
81658997Selan   else if (! strcmp (name, "switches_need_spaces"))
81758997Selan     switches_need_spaces = sl->spec;
81858997Selan   else if (! strcmp (name, "cross_compile"))
81958997Selan     cross_compile = atoi (sl->spec);
82058997Selan   /* Free the old spec */
82158997Selan   if (old_spec)
82258997Selan     free (old_spec);
82358997Selan }
82458997Selan 
82558997Selan /* Accumulate a command (program name and args), and run it.  */
82658997Selan 
82758997Selan /* Vector of pointers to arguments in the current line of specifications.  */
82858997Selan 
82958997Selan static char **argbuf;
83058997Selan 
83158997Selan /* Number of elements allocated in argbuf.  */
83258997Selan 
83358997Selan static int argbuf_length;
83458997Selan 
83558997Selan /* Number of elements in argbuf currently in use (containing args).  */
83658997Selan 
83758997Selan static int argbuf_index;
83858997Selan 
83958997Selan /* This is the list of suffixes and codes (%g/%u/%U) and the associated
84058997Selan    temp file.  Used only if MKTEMP_EACH_FILE.  */
84158997Selan 
84258997Selan static struct temp_name {
84358997Selan   char *suffix;		/* suffix associated with the code.  */
84458997Selan   int length;		/* strlen (suffix).  */
84558997Selan   int unique;		/* Indicates whether %g or %u/%U was used.  */
84658997Selan   char *filename;	/* associated filename.  */
84758997Selan   int filename_length;	/* strlen (filename).  */
84858997Selan   struct temp_name *next;
84958997Selan } *temp_names;
85058997Selan 
85158997Selan /* Number of commands executed so far.  */
85258997Selan 
85358997Selan static int execution_count;
85458997Selan 
85558997Selan /* Number of commands that exited with a signal.  */
85658997Selan 
85758997Selan static int signal_count;
85858997Selan 
85958997Selan /* Name with which this program was invoked.  */
86058997Selan 
86158997Selan static char *programname;
86258997Selan 
86358997Selan /* Structures to keep track of prefixes to try when looking for files. */
86458997Selan 
86558997Selan struct prefix_list
86658997Selan {
86758997Selan   char *prefix;               /* String to prepend to the path. */
86858997Selan   struct prefix_list *next;   /* Next in linked list. */
86958997Selan   int require_machine_suffix; /* Don't use without machine_suffix.  */
87058997Selan   /* 2 means try both machine_suffix and just_machine_suffix.  */
87158997Selan   int *used_flag_ptr;	      /* 1 if a file was found with this prefix.  */
87258997Selan };
87358997Selan 
87458997Selan struct path_prefix
87558997Selan {
87658997Selan   struct prefix_list *plist;  /* List of prefixes to try */
87758997Selan   int max_len;                /* Max length of a prefix in PLIST */
87858997Selan   char *name;                 /* Name of this list (used in config stuff) */
87958997Selan };
88058997Selan 
88158997Selan /* List of prefixes to try when looking for executables. */
88258997Selan 
88358997Selan static struct path_prefix exec_prefix = { 0, 0, "exec" };
88458997Selan 
88558997Selan /* List of prefixes to try when looking for startup (crt0) files. */
88658997Selan 
88758997Selan static struct path_prefix startfile_prefix = { 0, 0, "startfile" };
88858997Selan 
88958997Selan /* List of prefixes to try when looking for libraries. */
89058997Selan 
89158997Selan static struct path_prefix library_prefix = { 0, 0, "libraryfile" };
89258997Selan 
89358997Selan /* Suffix to attach to directories searched for commands.
89458997Selan    This looks like `MACHINE/VERSION/'.  */
89558997Selan 
89658997Selan static char *machine_suffix = 0;
89758997Selan 
89858997Selan /* Suffix to attach to directories searched for commands.
89958997Selan    This is just `MACHINE/'.  */
90058997Selan 
90158997Selan static char *just_machine_suffix = 0;
90258997Selan 
90358997Selan /* Adjusted value of GCC_EXEC_PREFIX envvar.  */
90458997Selan 
90558997Selan static char *gcc_exec_prefix;
90658997Selan 
90758997Selan /* Default prefixes to attach to command names.  */
90858997Selan 
90958997Selan #ifdef CROSS_COMPILE  /* Don't use these prefixes for a cross compiler.  */
91058997Selan #undef MD_EXEC_PREFIX
91158997Selan #undef MD_STARTFILE_PREFIX
91258997Selan #undef MD_STARTFILE_PREFIX_1
91358997Selan #endif
91458997Selan 
91558997Selan #ifndef STANDARD_EXEC_PREFIX
916*60377Selan #define STANDARD_EXEC_PREFIX "/usr/libexec/gcc2/"
91758997Selan #endif /* !defined STANDARD_EXEC_PREFIX */
91858997Selan 
91958997Selan static char *standard_exec_prefix = STANDARD_EXEC_PREFIX;
92058997Selan static char *standard_exec_prefix_1 = "/usr/lib/gcc/";
92158997Selan #ifdef MD_EXEC_PREFIX
92258997Selan static char *md_exec_prefix = MD_EXEC_PREFIX;
92358997Selan #endif
92458997Selan 
92558997Selan #ifndef STANDARD_STARTFILE_PREFIX
92658997Selan #define STANDARD_STARTFILE_PREFIX "/usr/local/lib/"
92758997Selan #endif /* !defined STANDARD_STARTFILE_PREFIX */
92858997Selan 
92958997Selan #ifdef MD_STARTFILE_PREFIX
93058997Selan static char *md_startfile_prefix = MD_STARTFILE_PREFIX;
93158997Selan #endif
93258997Selan #ifdef MD_STARTFILE_PREFIX_1
93358997Selan static char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
93458997Selan #endif
93558997Selan static char *standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
93658997Selan static char *standard_startfile_prefix_1 = "/lib/";
93758997Selan static char *standard_startfile_prefix_2 = "/usr/lib/";
93858997Selan 
93958997Selan /* Clear out the vector of arguments (after a command is executed).  */
94058997Selan 
94158997Selan static void
clear_args()94258997Selan clear_args ()
94358997Selan {
94458997Selan   argbuf_index = 0;
94558997Selan }
94658997Selan 
94758997Selan /* Add one argument to the vector at the end.
94858997Selan    This is done when a space is seen or at the end of the line.
94958997Selan    If DELETE_ALWAYS is nonzero, the arg is a filename
95058997Selan     and the file should be deleted eventually.
95158997Selan    If DELETE_FAILURE is nonzero, the arg is a filename
95258997Selan     and the file should be deleted if this compilation fails.  */
95358997Selan 
95458997Selan static void
store_arg(arg,delete_always,delete_failure)95558997Selan store_arg (arg, delete_always, delete_failure)
95658997Selan      char *arg;
95758997Selan      int delete_always, delete_failure;
95858997Selan {
95958997Selan   if (argbuf_index + 1 == argbuf_length)
96058997Selan     {
96158997Selan       argbuf = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
96258997Selan     }
96358997Selan 
96458997Selan   argbuf[argbuf_index++] = arg;
96558997Selan   argbuf[argbuf_index] = 0;
96658997Selan 
96758997Selan   if (delete_always || delete_failure)
96858997Selan     record_temp_file (arg, delete_always, delete_failure);
96958997Selan }
97058997Selan 
97158997Selan /* Record the names of temporary files we tell compilers to write,
97258997Selan    and delete them at the end of the run.  */
97358997Selan 
97458997Selan /* This is the common prefix we use to make temp file names.
97558997Selan    It is chosen once for each run of this program.
97658997Selan    It is substituted into a spec by %g.
97758997Selan    Thus, all temp file names contain this prefix.
97858997Selan    In practice, all temp file names start with this prefix.
97958997Selan 
98058997Selan    This prefix comes from the envvar TMPDIR if it is defined;
98158997Selan    otherwise, from the P_tmpdir macro if that is defined;
98258997Selan    otherwise, in /usr/tmp or /tmp.  */
98358997Selan 
98458997Selan static char *temp_filename;
98558997Selan 
98658997Selan /* Length of the prefix.  */
98758997Selan 
98858997Selan static int temp_filename_length;
98958997Selan 
99058997Selan /* Define the list of temporary files to delete.  */
99158997Selan 
99258997Selan struct temp_file
99358997Selan {
99458997Selan   char *name;
99558997Selan   struct temp_file *next;
99658997Selan };
99758997Selan 
99858997Selan /* Queue of files to delete on success or failure of compilation.  */
99958997Selan static struct temp_file *always_delete_queue;
100058997Selan /* Queue of files to delete on failure of compilation.  */
100158997Selan static struct temp_file *failure_delete_queue;
100258997Selan 
100358997Selan /* Record FILENAME as a file to be deleted automatically.
100458997Selan    ALWAYS_DELETE nonzero means delete it if all compilation succeeds;
100558997Selan    otherwise delete it in any case.
100658997Selan    FAIL_DELETE nonzero means delete it if a compilation step fails;
100758997Selan    otherwise delete it in any case.  */
100858997Selan 
100958997Selan static void
record_temp_file(filename,always_delete,fail_delete)101058997Selan record_temp_file (filename, always_delete, fail_delete)
101158997Selan      char *filename;
101258997Selan      int always_delete;
101358997Selan      int fail_delete;
101458997Selan {
101558997Selan   register char *name;
101658997Selan   name = xmalloc (strlen (filename) + 1);
101758997Selan   strcpy (name, filename);
101858997Selan 
101958997Selan   if (always_delete)
102058997Selan     {
102158997Selan       register struct temp_file *temp;
102258997Selan       for (temp = always_delete_queue; temp; temp = temp->next)
102358997Selan 	if (! strcmp (name, temp->name))
102458997Selan 	  goto already1;
102558997Selan       temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
102658997Selan       temp->next = always_delete_queue;
102758997Selan       temp->name = name;
102858997Selan       always_delete_queue = temp;
102958997Selan     already1:;
103058997Selan     }
103158997Selan 
103258997Selan   if (fail_delete)
103358997Selan     {
103458997Selan       register struct temp_file *temp;
103558997Selan       for (temp = failure_delete_queue; temp; temp = temp->next)
103658997Selan 	if (! strcmp (name, temp->name))
103758997Selan 	  goto already2;
103858997Selan       temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
103958997Selan       temp->next = failure_delete_queue;
104058997Selan       temp->name = name;
104158997Selan       failure_delete_queue = temp;
104258997Selan     already2:;
104358997Selan     }
104458997Selan }
104558997Selan 
104658997Selan /* Delete all the temporary files whose names we previously recorded.  */
104758997Selan 
104858997Selan static void
delete_temp_files()104958997Selan delete_temp_files ()
105058997Selan {
105158997Selan   register struct temp_file *temp;
105258997Selan 
105358997Selan   for (temp = always_delete_queue; temp; temp = temp->next)
105458997Selan     {
105558997Selan #ifdef DEBUG
105658997Selan       int i;
105758997Selan       printf ("Delete %s? (y or n) ", temp->name);
105858997Selan       fflush (stdout);
105958997Selan       i = getchar ();
106058997Selan       if (i != '\n')
106158997Selan 	while (getchar () != '\n') ;
106258997Selan       if (i == 'y' || i == 'Y')
106358997Selan #endif /* DEBUG */
106458997Selan 	{
106558997Selan 	  struct stat st;
106658997Selan 	  if (stat (temp->name, &st) >= 0)
106758997Selan 	    {
106858997Selan 	      /* Delete only ordinary files.  */
106958997Selan 	      if (S_ISREG (st.st_mode))
107058997Selan 		if (unlink (temp->name) < 0)
107158997Selan 		  if (verbose_flag)
107258997Selan 		    perror_with_name (temp->name);
107358997Selan 	    }
107458997Selan 	}
107558997Selan     }
107658997Selan 
107758997Selan   always_delete_queue = 0;
107858997Selan }
107958997Selan 
108058997Selan /* Delete all the files to be deleted on error.  */
108158997Selan 
108258997Selan static void
delete_failure_queue()108358997Selan delete_failure_queue ()
108458997Selan {
108558997Selan   register struct temp_file *temp;
108658997Selan 
108758997Selan   for (temp = failure_delete_queue; temp; temp = temp->next)
108858997Selan     {
108958997Selan #ifdef DEBUG
109058997Selan       int i;
109158997Selan       printf ("Delete %s? (y or n) ", temp->name);
109258997Selan       fflush (stdout);
109358997Selan       i = getchar ();
109458997Selan       if (i != '\n')
109558997Selan 	while (getchar () != '\n') ;
109658997Selan       if (i == 'y' || i == 'Y')
109758997Selan #endif /* DEBUG */
109858997Selan 	{
109958997Selan 	  if (unlink (temp->name) < 0)
110058997Selan 	    if (verbose_flag)
110158997Selan 	      perror_with_name (temp->name);
110258997Selan 	}
110358997Selan     }
110458997Selan }
110558997Selan 
110658997Selan static void
clear_failure_queue()110758997Selan clear_failure_queue ()
110858997Selan {
110958997Selan   failure_delete_queue = 0;
111058997Selan }
111158997Selan 
111258997Selan /* Compute a string to use as the base of all temporary file names.
111358997Selan    It is substituted for %g.  */
111458997Selan 
111558997Selan static void
choose_temp_base()111658997Selan choose_temp_base ()
111758997Selan {
111858997Selan   char *base = getenv ("TMPDIR");
111958997Selan   int len;
112058997Selan 
112158997Selan   if (base == (char *)0)
112258997Selan     {
112358997Selan #ifdef P_tmpdir
112458997Selan       if (access (P_tmpdir, R_OK | W_OK) == 0)
112558997Selan 	base = P_tmpdir;
112658997Selan #endif
112758997Selan       if (base == (char *)0)
112858997Selan 	{
112958997Selan 	  if (access ("/usr/tmp", R_OK | W_OK) == 0)
113058997Selan 	    base = "/usr/tmp/";
113158997Selan 	  else
113258997Selan 	    base = "/tmp/";
113358997Selan 	}
113458997Selan     }
113558997Selan 
113658997Selan   len = strlen (base);
113758997Selan   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
113858997Selan   strcpy (temp_filename, base);
113958997Selan   if (len > 0 && temp_filename[len-1] != '/')
114058997Selan     temp_filename[len++] = '/';
114158997Selan   strcpy (temp_filename + len, "ccXXXXXX");
114258997Selan 
114358997Selan   mktemp (temp_filename);
114458997Selan   temp_filename_length = strlen (temp_filename);
114558997Selan   if (temp_filename_length == 0)
114658997Selan     abort ();
114758997Selan }
114858997Selan 
114958997Selan 
115058997Selan /* Routine to add variables to the environment.  We do this to pass
115158997Selan    the pathname of the gcc driver, and the directories search to the
115258997Selan    collect2 program, which is being run as ld.  This way, we can be
115358997Selan    sure of executing the right compiler when collect2 wants to build
115458997Selan    constructors and destructors.  Since the environment variables we
115558997Selan    use come from an obstack, we don't have to worry about allocating
115658997Selan    space for them.  */
115758997Selan 
115858997Selan #ifndef HAVE_PUTENV
115958997Selan 
putenv(str)116058997Selan putenv (str)
116158997Selan      char *str;
116258997Selan {
116358997Selan #ifndef VMS			/* nor about VMS */
116458997Selan 
116558997Selan   extern char **environ;
116658997Selan   char **old_environ = environ;
116758997Selan   char **envp;
116858997Selan   int num_envs = 0;
116958997Selan   int name_len = 1;
117058997Selan   int str_len = strlen (str);
117158997Selan   char *p = str;
117258997Selan   int ch;
117358997Selan 
117458997Selan   while ((ch = *p++) != '\0' && ch != '=')
117558997Selan     name_len++;
117658997Selan 
117758997Selan   if (!ch)
117858997Selan     abort ();
117958997Selan 
118058997Selan   /* Search for replacing an existing environment variable, and
118158997Selan      count the number of total environment variables.  */
118258997Selan   for (envp = old_environ; *envp; envp++)
118358997Selan     {
118458997Selan       num_envs++;
118558997Selan       if (!strncmp (str, *envp, name_len))
118658997Selan 	{
118758997Selan 	  *envp = str;
118858997Selan 	  return;
118958997Selan 	}
119058997Selan     }
119158997Selan 
119258997Selan   /* Add a new environment variable */
119358997Selan   environ = (char **) xmalloc (sizeof (char *) * (num_envs+2));
119458997Selan   *environ = str;
119558997Selan   bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1));
119658997Selan 
119758997Selan #endif	/* VMS */
119858997Selan }
119958997Selan 
120058997Selan #endif	/* HAVE_PUTENV */
120158997Selan 
120258997Selan 
120358997Selan /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect.  */
120458997Selan 
120558997Selan static void
putenv_from_prefixes(paths,env_var)120658997Selan putenv_from_prefixes (paths, env_var)
120758997Selan      struct path_prefix *paths;
120858997Selan      char *env_var;
120958997Selan {
121058997Selan   int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
121158997Selan   int first_time = TRUE;
121258997Selan   struct prefix_list *pprefix;
121358997Selan 
121458997Selan   obstack_grow (&collect_obstack, env_var, strlen (env_var));
121558997Selan 
121658997Selan   for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
121758997Selan     {
121858997Selan       int len = strlen (pprefix->prefix);
121958997Selan 
122058997Selan       if (machine_suffix)
122158997Selan 	{
122258997Selan 	  if (!first_time)
122358997Selan 	    obstack_grow (&collect_obstack, ":", 1);
122458997Selan 
122558997Selan 	  first_time = FALSE;
122658997Selan 	  obstack_grow (&collect_obstack, pprefix->prefix, len);
122758997Selan 	  obstack_grow (&collect_obstack, machine_suffix, suffix_len);
122858997Selan 	}
122958997Selan 
123058997Selan       if (just_machine_suffix && pprefix->require_machine_suffix == 2)
123158997Selan 	{
123258997Selan 	  if (!first_time)
123358997Selan 	    obstack_grow (&collect_obstack, ":", 1);
123458997Selan 
123558997Selan 	  first_time = FALSE;
123658997Selan 	  obstack_grow (&collect_obstack, pprefix->prefix, len);
123758997Selan 	  obstack_grow (&collect_obstack, machine_suffix, suffix_len);
123858997Selan 	}
123958997Selan 
124058997Selan       if (!pprefix->require_machine_suffix)
124158997Selan 	{
124258997Selan 	  if (!first_time)
124358997Selan 	    obstack_grow (&collect_obstack, ":", 1);
124458997Selan 
124558997Selan 	  first_time = FALSE;
124658997Selan 	  obstack_grow (&collect_obstack, pprefix->prefix, len);
124758997Selan 	}
124858997Selan     }
124958997Selan   obstack_grow (&collect_obstack, "\0", 1);
125058997Selan   putenv (obstack_finish (&collect_obstack));
125158997Selan }
125258997Selan 
125358997Selan 
125458997Selan /* Search for NAME using the prefix list PREFIXES.  MODE is passed to
125558997Selan    access to check permissions.
125658997Selan    Return 0 if not found, otherwise return its name, allocated with malloc. */
125758997Selan 
125858997Selan static char *
find_a_file(pprefix,name,mode)125958997Selan find_a_file (pprefix, name, mode)
126058997Selan      struct path_prefix *pprefix;
126158997Selan      char *name;
126258997Selan      int mode;
126358997Selan {
126458997Selan   char *temp;
126558997Selan   char *file_suffix = ((mode & X_OK) != 0 ? EXECUTABLE_SUFFIX : "");
126658997Selan   struct prefix_list *pl;
126758997Selan   int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
126858997Selan 
126958997Selan   if (machine_suffix)
127058997Selan     len += strlen (machine_suffix);
127158997Selan 
127258997Selan   temp = xmalloc (len);
127358997Selan 
127458997Selan   /* Determine the filename to execute (special case for absolute paths).  */
127558997Selan 
127658997Selan   if (*name == '/')
127758997Selan     {
127858997Selan       if (access (name, mode))
127958997Selan 	{
128058997Selan 	  strcpy (temp, name);
128158997Selan 	  return temp;
128258997Selan 	}
128358997Selan     }
128458997Selan   else
128558997Selan     for (pl = pprefix->plist; pl; pl = pl->next)
128658997Selan       {
128758997Selan 	if (machine_suffix)
128858997Selan 	  {
128958997Selan 	    strcpy (temp, pl->prefix);
129058997Selan 	    strcat (temp, machine_suffix);
129158997Selan 	    strcat (temp, name);
129258997Selan 	    if (access (temp, mode) == 0)
129358997Selan 	      {
129458997Selan 		if (pl->used_flag_ptr != 0)
129558997Selan 		  *pl->used_flag_ptr = 1;
129658997Selan 		return temp;
129758997Selan 	      }
129858997Selan 	    /* Some systems have a suffix for executable files.
129958997Selan 	       So try appending that.  */
130058997Selan 	    if (file_suffix[0] != 0)
130158997Selan 	      {
130258997Selan 		strcat (temp, file_suffix);
130358997Selan 		if (access (temp, mode) == 0)
130458997Selan 		  {
130558997Selan 		    if (pl->used_flag_ptr != 0)
130658997Selan 		      *pl->used_flag_ptr = 1;
130758997Selan 		    return temp;
130858997Selan 		  }
130958997Selan 	      }
131058997Selan 	  }
131158997Selan 	/* Certain prefixes are tried with just the machine type,
131258997Selan 	   not the version.  This is used for finding as, ld, etc.  */
131358997Selan 	if (just_machine_suffix && pl->require_machine_suffix == 2)
131458997Selan 	  {
131558997Selan 	    strcpy (temp, pl->prefix);
131658997Selan 	    strcat (temp, just_machine_suffix);
131758997Selan 	    strcat (temp, name);
131858997Selan 	    if (access (temp, mode) == 0)
131958997Selan 	      {
132058997Selan 		if (pl->used_flag_ptr != 0)
132158997Selan 		  *pl->used_flag_ptr = 1;
132258997Selan 		return temp;
132358997Selan 	      }
132458997Selan 	    /* Some systems have a suffix for executable files.
132558997Selan 	       So try appending that.  */
132658997Selan 	    if (file_suffix[0] != 0)
132758997Selan 	      {
132858997Selan 		strcat (temp, file_suffix);
132958997Selan 		if (access (temp, mode) == 0)
133058997Selan 		  {
133158997Selan 		    if (pl->used_flag_ptr != 0)
133258997Selan 		      *pl->used_flag_ptr = 1;
133358997Selan 		    return temp;
133458997Selan 		  }
133558997Selan 	      }
133658997Selan 	  }
133758997Selan 	/* Certain prefixes can't be used without the machine suffix
133858997Selan 	   when the machine or version is explicitly specified.  */
133958997Selan 	if (!pl->require_machine_suffix)
134058997Selan 	  {
134158997Selan 	    strcpy (temp, pl->prefix);
134258997Selan 	    strcat (temp, name);
134358997Selan 	    if (access (temp, mode) == 0)
134458997Selan 	      {
134558997Selan 		if (pl->used_flag_ptr != 0)
134658997Selan 		  *pl->used_flag_ptr = 1;
134758997Selan 		return temp;
134858997Selan 	      }
134958997Selan 	    /* Some systems have a suffix for executable files.
135058997Selan 	       So try appending that.  */
135158997Selan 	    if (file_suffix[0] != 0)
135258997Selan 	      {
135358997Selan 		strcat (temp, file_suffix);
135458997Selan 		if (access (temp, mode) == 0)
135558997Selan 		  {
135658997Selan 		    if (pl->used_flag_ptr != 0)
135758997Selan 		      *pl->used_flag_ptr = 1;
135858997Selan 		    return temp;
135958997Selan 		  }
136058997Selan 	      }
136158997Selan 	  }
136258997Selan       }
136358997Selan 
136458997Selan   free (temp);
136558997Selan   return 0;
136658997Selan }
136758997Selan 
136858997Selan /* Add an entry for PREFIX in PLIST.  If FIRST is set, it goes
136958997Selan    at the start of the list, otherwise it goes at the end.
137058997Selan 
137158997Selan    If WARN is nonzero, we will warn if no file is found
137258997Selan    through this prefix.  WARN should point to an int
137358997Selan    which will be set to 1 if this entry is used.
137458997Selan 
137558997Selan    REQUIRE_MACHINE_SUFFIX is 1 if this prefix can't be used without
137658997Selan    the complete value of machine_suffix.
137758997Selan    2 means try both machine_suffix and just_machine_suffix.  */
137858997Selan 
137958997Selan static void
add_prefix(pprefix,prefix,first,require_machine_suffix,warn)138058997Selan add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
138158997Selan      struct path_prefix *pprefix;
138258997Selan      char *prefix;
138358997Selan      int first;
138458997Selan      int require_machine_suffix;
138558997Selan      int *warn;
138658997Selan {
138758997Selan   struct prefix_list *pl, **prev;
138858997Selan   int len;
138958997Selan 
139058997Selan   if (!first && pprefix->plist)
139158997Selan     {
139258997Selan       for (pl = pprefix->plist; pl->next; pl = pl->next)
139358997Selan 	;
139458997Selan       prev = &pl->next;
139558997Selan     }
139658997Selan   else
139758997Selan     prev = &pprefix->plist;
139858997Selan 
139958997Selan   /* Keep track of the longest prefix */
140058997Selan 
140158997Selan   len = strlen (prefix);
140258997Selan   if (len > pprefix->max_len)
140358997Selan     pprefix->max_len = len;
140458997Selan 
140558997Selan   pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list));
140658997Selan   pl->prefix = save_string (prefix, len);
140758997Selan   pl->require_machine_suffix = require_machine_suffix;
140858997Selan   pl->used_flag_ptr = warn;
140958997Selan   if (warn)
141058997Selan     *warn = 0;
141158997Selan 
141258997Selan   if (*prev)
141358997Selan     pl->next = *prev;
141458997Selan   else
141558997Selan     pl->next = (struct prefix_list *) 0;
141658997Selan   *prev = pl;
141758997Selan }
141858997Selan 
141958997Selan /* Print warnings for any prefixes in the list PPREFIX that were not used.  */
142058997Selan 
142158997Selan static void
unused_prefix_warnings(pprefix)142258997Selan unused_prefix_warnings (pprefix)
142358997Selan      struct path_prefix *pprefix;
142458997Selan {
142558997Selan   struct prefix_list *pl = pprefix->plist;
142658997Selan 
142758997Selan   while (pl)
142858997Selan     {
142958997Selan       if (pl->used_flag_ptr != 0 && !*pl->used_flag_ptr)
143058997Selan 	{
143158997Selan 	  error ("file path prefix `%s' never used",
143258997Selan 		 pl->prefix);
143358997Selan 	  /* Prevent duplicate warnings.  */
143458997Selan 	  *pl->used_flag_ptr = 1;
143558997Selan 	}
143658997Selan       pl = pl->next;
143758997Selan     }
143858997Selan }
143958997Selan 
144058997Selan /* Get rid of all prefixes built up so far in *PLISTP. */
144158997Selan 
144258997Selan static void
free_path_prefix(pprefix)144358997Selan free_path_prefix (pprefix)
144458997Selan      struct path_prefix *pprefix;
144558997Selan {
144658997Selan   struct prefix_list *pl = pprefix->plist;
144758997Selan   struct prefix_list *temp;
144858997Selan 
144958997Selan   while (pl)
145058997Selan     {
145158997Selan       temp = pl;
145258997Selan       pl = pl->next;
145358997Selan       free (temp->prefix);
145458997Selan       free ((char *) temp);
145558997Selan     }
145658997Selan   pprefix->plist = (struct prefix_list *) 0;
145758997Selan }
145858997Selan 
145958997Selan /* stdin file number.  */
146058997Selan #define STDIN_FILE_NO 0
146158997Selan 
146258997Selan /* stdout file number.  */
146358997Selan #define STDOUT_FILE_NO 1
146458997Selan 
146558997Selan /* value of `pipe': port index for reading.  */
146658997Selan #define READ_PORT 0
146758997Selan 
146858997Selan /* value of `pipe': port index for writing.  */
146958997Selan #define WRITE_PORT 1
147058997Selan 
147158997Selan /* Pipe waiting from last process, to be used as input for the next one.
147258997Selan    Value is STDIN_FILE_NO if no pipe is waiting
147358997Selan    (i.e. the next command is the first of a group).  */
147458997Selan 
147558997Selan static int last_pipe_input;
147658997Selan 
147758997Selan /* Fork one piped subcommand.  FUNC is the system call to use
147858997Selan    (either execv or execvp).  ARGV is the arg vector to use.
147958997Selan    NOT_LAST is nonzero if this is not the last subcommand
148058997Selan    (i.e. its output should be piped to the next one.)  */
148158997Selan 
148258997Selan #ifndef OS2
148358997Selan #ifdef __MSDOS__
148458997Selan 
148558997Selan /* Declare these to avoid compilation error.  They won't be called.  */
execv(const char * a,const char ** b)148658997Selan int execv(const char *a, const char **b){}
execvp(const char * a,const char ** b)148758997Selan int execvp(const char *a, const char **b){}
148858997Selan 
148958997Selan static int
pexecute(search_flag,program,argv,not_last)149058997Selan pexecute (search_flag, program, argv, not_last)
149158997Selan      int search_flag;
149258997Selan      char *program;
149358997Selan      char *argv[];
149458997Selan      int not_last;
149558997Selan {
149658997Selan   char *scmd;
149758997Selan   FILE *argfile;
149858997Selan   int i;
149958997Selan 
150058997Selan   scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6);
150158997Selan   sprintf (scmd, "%s @%s.gp", program, temp_filename);
150258997Selan   argfile = fopen (scmd+strlen (program) + 2, "w");
150358997Selan   if (argfile == 0)
150458997Selan     pfatal_with_name (scmd + strlen (program) + 2);
150558997Selan 
150658997Selan   for (i=1; argv[i]; i++)
150758997Selan   {
150858997Selan     char *cp;
150958997Selan     for (cp = argv[i]; *cp; cp++)
151058997Selan       {
151158997Selan 	if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
151258997Selan 	  fputc ('\\', argfile);
151358997Selan 	fputc (*cp, argfile);
151458997Selan       }
151558997Selan     fputc ('\n', argfile);
151658997Selan   }
151758997Selan   fclose (argfile);
151858997Selan 
151958997Selan   i = system (scmd);
152058997Selan 
152158997Selan   remove (scmd + strlen (program) + 2);
152258997Selan   return i << 8;
152358997Selan }
152458997Selan 
152558997Selan #else /* not __MSDOS__ */
152658997Selan 
152758997Selan static int
pexecute(search_flag,program,argv,not_last)152858997Selan pexecute (search_flag, program, argv, not_last)
152958997Selan      int search_flag;
153058997Selan      char *program;
153158997Selan      char *argv[];
153258997Selan      int not_last;
153358997Selan {
153458997Selan   int (*func)() = (search_flag ? execv : execvp);
153558997Selan   int pid;
153658997Selan   int pdes[2];
153758997Selan   int input_desc = last_pipe_input;
153858997Selan   int output_desc = STDOUT_FILE_NO;
153958997Selan   int retries, sleep_interval;
154058997Selan 
154158997Selan   /* If this isn't the last process, make a pipe for its output,
154258997Selan      and record it as waiting to be the input to the next process.  */
154358997Selan 
154458997Selan   if (not_last)
154558997Selan     {
154658997Selan       if (pipe (pdes) < 0)
154758997Selan 	pfatal_with_name ("pipe");
154858997Selan       output_desc = pdes[WRITE_PORT];
154958997Selan       last_pipe_input = pdes[READ_PORT];
155058997Selan     }
155158997Selan   else
155258997Selan     last_pipe_input = STDIN_FILE_NO;
155358997Selan 
155458997Selan   /* Fork a subprocess; wait and retry if it fails.  */
155558997Selan   sleep_interval = 1;
155658997Selan   for (retries = 0; retries < 4; retries++)
155758997Selan     {
155858997Selan       pid = vfork ();
155958997Selan       if (pid >= 0)
156058997Selan 	break;
156158997Selan       sleep (sleep_interval);
156258997Selan       sleep_interval *= 2;
156358997Selan     }
156458997Selan 
156558997Selan   switch (pid)
156658997Selan     {
156758997Selan     case -1:
156858997Selan #ifdef vfork
156958997Selan       pfatal_with_name ("fork");
157058997Selan #else
157158997Selan       pfatal_with_name ("vfork");
157258997Selan #endif
157358997Selan       /* NOTREACHED */
157458997Selan       return 0;
157558997Selan 
157658997Selan     case 0: /* child */
157758997Selan       /* Move the input and output pipes into place, if nec.  */
157858997Selan       if (input_desc != STDIN_FILE_NO)
157958997Selan 	{
158058997Selan 	  close (STDIN_FILE_NO);
158158997Selan 	  dup (input_desc);
158258997Selan 	  close (input_desc);
158358997Selan 	}
158458997Selan       if (output_desc != STDOUT_FILE_NO)
158558997Selan 	{
158658997Selan 	  close (STDOUT_FILE_NO);
158758997Selan 	  dup (output_desc);
158858997Selan 	  close (output_desc);
158958997Selan 	}
159058997Selan 
159158997Selan       /* Close the parent's descs that aren't wanted here.  */
159258997Selan       if (last_pipe_input != STDIN_FILE_NO)
159358997Selan 	close (last_pipe_input);
159458997Selan 
159558997Selan       /* Exec the program.  */
159658997Selan       (*func) (program, argv);
159758997Selan       perror_exec (program);
159858997Selan       exit (-1);
159958997Selan       /* NOTREACHED */
160058997Selan       return 0;
160158997Selan 
160258997Selan     default:
160358997Selan       /* In the parent, after forking.
160458997Selan 	 Close the descriptors that we made for this child.  */
160558997Selan       if (input_desc != STDIN_FILE_NO)
160658997Selan 	close (input_desc);
160758997Selan       if (output_desc != STDOUT_FILE_NO)
160858997Selan 	close (output_desc);
160958997Selan 
161058997Selan       /* Return child's process number.  */
161158997Selan       return pid;
161258997Selan     }
161358997Selan }
161458997Selan 
161558997Selan #endif /* not __MSDOS__ */
161658997Selan #else /* not OS2 */
161758997Selan 
161858997Selan static int
pexecute(search_flag,program,argv,not_last)161958997Selan pexecute (search_flag, program, argv, not_last)
162058997Selan      int search_flag;
162158997Selan      char *program;
162258997Selan      char *argv[];
162358997Selan      int not_last;
162458997Selan {
162558997Selan   return (search_flag ? spawnv : spawnvp) (1, program, argv);
162658997Selan }
162758997Selan #endif /* not OS2 */
162858997Selan 
162958997Selan /* Execute the command specified by the arguments on the current line of spec.
163058997Selan    When using pipes, this includes several piped-together commands
163158997Selan    with `|' between them.
163258997Selan 
163358997Selan    Return 0 if successful, -1 if failed.  */
163458997Selan 
163558997Selan static int
execute()163658997Selan execute ()
163758997Selan {
163858997Selan   int i;
163958997Selan   int n_commands;		/* # of command.  */
164058997Selan   char *string;
164158997Selan   struct command
164258997Selan     {
164358997Selan       char *prog;		/* program name.  */
164458997Selan       char **argv;		/* vector of args.  */
164558997Selan       int pid;			/* pid of process for this command.  */
164658997Selan     };
164758997Selan 
164858997Selan   struct command *commands;	/* each command buffer with above info.  */
164958997Selan 
165058997Selan   /* Count # of piped commands.  */
165158997Selan   for (n_commands = 1, i = 0; i < argbuf_index; i++)
165258997Selan     if (strcmp (argbuf[i], "|") == 0)
165358997Selan       n_commands++;
165458997Selan 
165558997Selan   /* Get storage for each command.  */
165658997Selan   commands
165758997Selan     = (struct command *) alloca (n_commands * sizeof (struct command));
165858997Selan 
165958997Selan   /* Split argbuf into its separate piped processes,
166058997Selan      and record info about each one.
166158997Selan      Also search for the programs that are to be run.  */
166258997Selan 
166358997Selan   commands[0].prog = argbuf[0]; /* first command.  */
166458997Selan   commands[0].argv = &argbuf[0];
166558997Selan   string = find_a_file (&exec_prefix, commands[0].prog, X_OK);
166658997Selan   if (string)
166758997Selan     commands[0].argv[0] = string;
166858997Selan 
166958997Selan   for (n_commands = 1, i = 0; i < argbuf_index; i++)
167058997Selan     if (strcmp (argbuf[i], "|") == 0)
167158997Selan       {				/* each command.  */
167258997Selan #ifdef __MSDOS__
167358997Selan         fatal ("-pipe not supported under MS-DOS");
167458997Selan #endif
167558997Selan 	argbuf[i] = 0;	/* termination of command args.  */
167658997Selan 	commands[n_commands].prog = argbuf[i + 1];
167758997Selan 	commands[n_commands].argv = &argbuf[i + 1];
167858997Selan 	string = find_a_file (&exec_prefix, commands[n_commands].prog, X_OK);
167958997Selan 	if (string)
168058997Selan 	  commands[n_commands].argv[0] = string;
168158997Selan 	n_commands++;
168258997Selan       }
168358997Selan 
168458997Selan   argbuf[argbuf_index] = 0;
168558997Selan 
168658997Selan   /* If -v, print what we are about to do, and maybe query.  */
168758997Selan 
168858997Selan   if (verbose_flag)
168958997Selan     {
169058997Selan       /* Print each piped command as a separate line.  */
169158997Selan       for (i = 0; i < n_commands ; i++)
169258997Selan 	{
169358997Selan 	  char **j;
169458997Selan 
169558997Selan 	  for (j = commands[i].argv; *j; j++)
169658997Selan 	    fprintf (stderr, " %s", *j);
169758997Selan 
169858997Selan 	  /* Print a pipe symbol after all but the last command.  */
169958997Selan 	  if (i + 1 != n_commands)
170058997Selan 	    fprintf (stderr, " |");
170158997Selan 	  fprintf (stderr, "\n");
170258997Selan 	}
170358997Selan       fflush (stderr);
170458997Selan #ifdef DEBUG
170558997Selan       fprintf (stderr, "\nGo ahead? (y or n) ");
170658997Selan       fflush (stderr);
170758997Selan       i = getchar ();
170858997Selan       if (i != '\n')
170958997Selan 	while (getchar () != '\n') ;
171058997Selan       if (i != 'y' && i != 'Y')
171158997Selan 	return 0;
171258997Selan #endif /* DEBUG */
171358997Selan     }
171458997Selan 
171558997Selan   /* Run each piped subprocess.  */
171658997Selan 
171758997Selan   last_pipe_input = STDIN_FILE_NO;
171858997Selan   for (i = 0; i < n_commands; i++)
171958997Selan     {
172058997Selan       char *string = commands[i].argv[0];
172158997Selan 
172258997Selan       commands[i].pid = pexecute (string != commands[i].prog,
172358997Selan 				  string, commands[i].argv,
172458997Selan 				  i + 1 < n_commands);
172558997Selan 
172658997Selan       if (string != commands[i].prog)
172758997Selan 	free (string);
172858997Selan     }
172958997Selan 
173058997Selan   execution_count++;
173158997Selan 
173258997Selan   /* Wait for all the subprocesses to finish.
173358997Selan      We don't care what order they finish in;
173458997Selan      we know that N_COMMANDS waits will get them all.  */
173558997Selan 
173658997Selan   {
173758997Selan     int ret_code = 0;
173858997Selan 
173958997Selan     for (i = 0; i < n_commands; i++)
174058997Selan       {
174158997Selan 	int status;
174258997Selan 	int pid;
174358997Selan 	char *prog;
174458997Selan 
174558997Selan #ifdef __MSDOS__
174658997Selan         status = pid = commands[i].pid;
174758997Selan #else
174858997Selan 	pid = wait (&status);
174958997Selan #endif
175058997Selan 	if (pid < 0)
175158997Selan 	  abort ();
175258997Selan 
175358997Selan 	if (status != 0)
175458997Selan 	  {
175558997Selan 	    int j;
175658997Selan 	    for (j = 0; j < n_commands; j++)
175758997Selan 	      if (commands[j].pid == pid)
175858997Selan 		prog = commands[j].prog;
175958997Selan 
176058997Selan 	    if ((status & 0x7F) != 0)
176158997Selan 	      {
176258997Selan 		fatal ("Internal compiler error: program %s got fatal signal %d",
176358997Selan 		       prog, (status & 0x7F));
176458997Selan 		signal_count++;
176558997Selan 	      }
176658997Selan 	    if (((status & 0xFF00) >> 8) >= MIN_FATAL_STATUS)
176758997Selan 	      ret_code = -1;
176858997Selan 	  }
176958997Selan       }
177058997Selan     return ret_code;
177158997Selan   }
177258997Selan }
177358997Selan 
177458997Selan /* Find all the switches given to us
177558997Selan    and make a vector describing them.
177658997Selan    The elements of the vector are strings, one per switch given.
177758997Selan    If a switch uses following arguments, then the `part1' field
177858997Selan    is the switch itself and the `args' field
177958997Selan    is a null-terminated vector containing the following arguments.
178058997Selan    The `valid' field is nonzero if any spec has looked at this switch;
178158997Selan    if it remains zero at the end of the run, it must be meaningless.  */
178258997Selan 
178358997Selan struct switchstr
178458997Selan {
178558997Selan   char *part1;
178658997Selan   char **args;
178758997Selan   int valid;
178858997Selan };
178958997Selan 
179058997Selan static struct switchstr *switches;
179158997Selan 
179258997Selan static int n_switches;
179358997Selan 
179458997Selan struct infile
179558997Selan {
179658997Selan   char *name;
179758997Selan   char *language;
179858997Selan };
179958997Selan 
180058997Selan /* Also a vector of input files specified.  */
180158997Selan 
180258997Selan static struct infile *infiles;
180358997Selan 
180458997Selan static int n_infiles;
180558997Selan 
180658997Selan /* And a vector of corresponding output files is made up later.  */
180758997Selan 
180858997Selan static char **outfiles;
180958997Selan 
181058997Selan /* Create the vector `switches' and its contents.
181158997Selan    Store its length in `n_switches'.  */
181258997Selan 
181358997Selan static void
process_command(argc,argv)181458997Selan process_command (argc, argv)
181558997Selan      int argc;
181658997Selan      char **argv;
181758997Selan {
181858997Selan   register int i;
181958997Selan   char *temp;
182058997Selan   char *spec_lang = 0;
182158997Selan   int last_language_n_infiles;
182258997Selan 
182358997Selan   gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
182458997Selan 
182558997Selan   n_switches = 0;
182658997Selan   n_infiles = 0;
182758997Selan 
182858997Selan   /* Default for -V is our version number, ending at first space.  */
182958997Selan   spec_version = save_string (version_string, strlen (version_string));
183058997Selan   for (temp = spec_version; *temp && *temp != ' '; temp++);
183158997Selan   if (*temp) *temp = '\0';
183258997Selan 
183358997Selan   /* Set up the default search paths.  */
1834*60377Selan   if (gcc_exec_prefix == 0)
1835*60377Selan 	  gcc_exec_prefix = standard_exec_prefix;
183658997Selan 
1837*60377Selan   add_prefix (&exec_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
1838*60377Selan   add_prefix (&startfile_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
183958997Selan 
184058997Selan   /* COMPILER_PATH and LIBRARY_PATH have values
184158997Selan      that are lists of directory names with colons.  */
184258997Selan 
184358997Selan   temp = getenv ("COMPILER_PATH");
184458997Selan   if (temp)
184558997Selan     {
184658997Selan       char *startp, *endp;
184758997Selan       char *nstore = (char *) alloca (strlen (temp) + 3);
184858997Selan 
184958997Selan       startp = endp = temp;
185058997Selan       while (1)
185158997Selan 	{
185258997Selan 	  if (*endp == PATH_SEPARATOR || *endp == 0)
185358997Selan 	    {
185458997Selan 	      strncpy (nstore, startp, endp-startp);
185558997Selan 	      if (endp == startp)
185658997Selan 		{
185758997Selan 		  strcpy (nstore, "./");
185858997Selan 		}
185958997Selan 	      else if (endp[-1] != '/')
186058997Selan 		{
186158997Selan 		  nstore[endp-startp] = '/';
186258997Selan 		  nstore[endp-startp+1] = 0;
186358997Selan 		}
186458997Selan 	      else
186558997Selan 		nstore[endp-startp] = 0;
186658997Selan 	      add_prefix (&exec_prefix, nstore, 0, 0, NULL_PTR);
186758997Selan 	      if (*endp == 0)
186858997Selan 		break;
186958997Selan 	      endp = startp = endp + 1;
187058997Selan 	    }
187158997Selan 	  else
187258997Selan 	    endp++;
187358997Selan 	}
187458997Selan     }
187558997Selan 
187658997Selan   temp = getenv ("LIBRARY_PATH");
187758997Selan   if (temp)
187858997Selan     {
187958997Selan       char *startp, *endp;
188058997Selan       char *nstore = (char *) alloca (strlen (temp) + 3);
188158997Selan 
188258997Selan       startp = endp = temp;
188358997Selan       while (1)
188458997Selan 	{
188558997Selan 	  if (*endp == PATH_SEPARATOR || *endp == 0)
188658997Selan 	    {
188758997Selan 	      strncpy (nstore, startp, endp-startp);
188858997Selan 	      if (endp == startp)
188958997Selan 		{
189058997Selan 		  strcpy (nstore, "./");
189158997Selan 		}
189258997Selan 	      else if (endp[-1] != '/')
189358997Selan 		{
189458997Selan 		  nstore[endp-startp] = '/';
189558997Selan 		  nstore[endp-startp+1] = 0;
189658997Selan 		}
189758997Selan 	      else
189858997Selan 		nstore[endp-startp] = 0;
189958997Selan 	      add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
190058997Selan 	      /* Make separate list of dirs that came from LIBRARY_PATH.  */
190158997Selan 	      add_prefix (&library_prefix, nstore, 0, 0, NULL_PTR);
190258997Selan 	      if (*endp == 0)
190358997Selan 		break;
190458997Selan 	      endp = startp = endp + 1;
190558997Selan 	    }
190658997Selan 	  else
190758997Selan 	    endp++;
190858997Selan 	}
190958997Selan     }
191058997Selan 
191158997Selan   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
191258997Selan   temp = getenv ("LPATH");
191358997Selan   if (temp)
191458997Selan     {
191558997Selan       char *startp, *endp;
191658997Selan       char *nstore = (char *) alloca (strlen (temp) + 3);
191758997Selan 
191858997Selan       startp = endp = temp;
191958997Selan       while (1)
192058997Selan 	{
192158997Selan 	  if (*endp == PATH_SEPARATOR || *endp == 0)
192258997Selan 	    {
192358997Selan 	      strncpy (nstore, startp, endp-startp);
192458997Selan 	      if (endp == startp)
192558997Selan 		{
192658997Selan 		  strcpy (nstore, "./");
192758997Selan 		}
192858997Selan 	      else if (endp[-1] != '/')
192958997Selan 		{
193058997Selan 		  nstore[endp-startp] = '/';
193158997Selan 		  nstore[endp-startp+1] = 0;
193258997Selan 		}
193358997Selan 	      else
193458997Selan 		nstore[endp-startp] = 0;
193558997Selan 	      add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
193658997Selan 	      /* Make separate list of dirs that came from LIBRARY_PATH.  */
193758997Selan 	      add_prefix (&library_prefix, nstore, 0, 0, NULL_PTR);
193858997Selan 	      if (*endp == 0)
193958997Selan 		break;
194058997Selan 	      endp = startp = endp + 1;
194158997Selan 	    }
194258997Selan 	  else
194358997Selan 	    endp++;
194458997Selan 	}
194558997Selan     }
194658997Selan 
194758997Selan   /* Scan argv twice.  Here, the first time, just count how many switches
194858997Selan      there will be in their vector, and how many input files in theirs.
194958997Selan      Here we also parse the switches that cc itself uses (e.g. -v).  */
195058997Selan 
195158997Selan   for (i = 1; i < argc; i++)
195258997Selan     {
195358997Selan       if (! strcmp (argv[i], "-dumpspecs"))
195458997Selan 	{
195558997Selan 	  printf ("*asm:\n%s\n\n", asm_spec);
195658997Selan 	  printf ("*asm_final:\n%s\n\n", asm_final_spec);
195758997Selan 	  printf ("*cpp:\n%s\n\n", cpp_spec);
195858997Selan 	  printf ("*cc1:\n%s\n\n", cc1_spec);
195958997Selan 	  printf ("*cc1plus:\n%s\n\n", cc1plus_spec);
196058997Selan 	  printf ("*endfile:\n%s\n\n", endfile_spec);
196158997Selan 	  printf ("*link:\n%s\n\n", link_spec);
196258997Selan 	  printf ("*lib:\n%s\n\n", lib_spec);
196358997Selan 	  printf ("*startfile:\n%s\n\n", startfile_spec);
196458997Selan 	  printf ("*switches_need_spaces:\n%s\n\n", switches_need_spaces);
196558997Selan 	  printf ("*signed_char:\n%s\n\n", signed_char_spec);
196658997Selan 	  printf ("*predefines:\n%s\n\n", cpp_predefines);
196758997Selan 	  printf ("*cross_compile:\n%d\n\n", cross_compile);
196858997Selan 
196958997Selan 	  exit (0);
197058997Selan 	}
197158997Selan       else if (! strcmp (argv[i], "-dumpversion"))
197258997Selan 	{
197358997Selan 	  printf ("%s\n", version_string);
197458997Selan 	  exit (0);
197558997Selan 	}
197658997Selan       else if (! strcmp (argv[i], "-print-libgcc-file-name"))
197758997Selan 	{
197858997Selan 	  print_libgcc_file_name = 1;
197958997Selan 	}
198058997Selan       else if (! strcmp (argv[i], "-Xlinker"))
198158997Selan 	{
198258997Selan 	  /* Pass the argument of this option to the linker when we link.  */
198358997Selan 
198458997Selan 	  if (i + 1 == argc)
198558997Selan 	    fatal ("argument to `-Xlinker' is missing");
198658997Selan 
198758997Selan 	  n_linker_options++;
198858997Selan 	  if (!linker_options)
198958997Selan 	    linker_options
199058997Selan 	      = (char **) xmalloc (n_linker_options * sizeof (char **));
199158997Selan 	  else
199258997Selan 	    linker_options
199358997Selan 	      = (char **) xrealloc (linker_options,
199458997Selan 				    n_linker_options * sizeof (char **));
199558997Selan 
199658997Selan 	  linker_options[n_linker_options - 1] = argv[++i];
199758997Selan 	}
199858997Selan       else if (! strncmp (argv[i], "-Wl,", 4))
199958997Selan 	{
200058997Selan 	  int prev, j;
200158997Selan 	  /* Pass the rest of this option to the linker when we link.  */
200258997Selan 
200358997Selan 	  n_linker_options++;
200458997Selan 	  if (!linker_options)
200558997Selan 	    linker_options
200658997Selan 	      = (char **) xmalloc (n_linker_options * sizeof (char **));
200758997Selan 	  else
200858997Selan 	    linker_options
200958997Selan 	      = (char **) xrealloc (linker_options,
201058997Selan 				    n_linker_options * sizeof (char **));
201158997Selan 
201258997Selan 	  /* Split the argument at commas.  */
201358997Selan 	  prev = 4;
201458997Selan 	  for (j = 4; argv[i][j]; j++)
201558997Selan 	    if (argv[i][j] == ',')
201658997Selan 	      {
201758997Selan 		linker_options[n_linker_options - 1]
201858997Selan 		  = save_string (argv[i] + prev, j - prev);
201958997Selan 		n_linker_options++;
202058997Selan 		linker_options
202158997Selan 		  = (char **) xrealloc (linker_options,
202258997Selan 					n_linker_options * sizeof (char **));
202358997Selan 		prev = j + 1;
202458997Selan 	      }
202558997Selan 	  /* Record the part after the last comma.  */
202658997Selan 	  linker_options[n_linker_options - 1] = argv[i] + prev;
202758997Selan 	}
202858997Selan       else if (! strncmp (argv[i], "-Wa,", 4))
202958997Selan 	{
203058997Selan 	  int prev, j;
203158997Selan 	  /* Pass the rest of this option to the assembler.  */
203258997Selan 
203358997Selan 	  n_assembler_options++;
203458997Selan 	  if (!assembler_options)
203558997Selan 	    assembler_options
203658997Selan 	      = (char **) xmalloc (n_assembler_options * sizeof (char **));
203758997Selan 	  else
203858997Selan 	    assembler_options
203958997Selan 	      = (char **) xrealloc (assembler_options,
204058997Selan 				    n_assembler_options * sizeof (char **));
204158997Selan 
204258997Selan 	  /* Split the argument at commas.  */
204358997Selan 	  prev = 4;
204458997Selan 	  for (j = 4; argv[i][j]; j++)
204558997Selan 	    if (argv[i][j] == ',')
204658997Selan 	      {
204758997Selan 		assembler_options[n_assembler_options - 1]
204858997Selan 		  = save_string (argv[i] + prev, j - prev);
204958997Selan 		n_assembler_options++;
205058997Selan 		assembler_options
205158997Selan 		  = (char **) xrealloc (assembler_options,
205258997Selan 					n_assembler_options * sizeof (char **));
205358997Selan 		prev = j + 1;
205458997Selan 	      }
205558997Selan 	  /* Record the part after the last comma.  */
205658997Selan 	  assembler_options[n_assembler_options - 1] = argv[i] + prev;
205758997Selan 	}
205858997Selan       else if (argv[i][0] == '+' && argv[i][1] == 'e')
205958997Selan 	/* Compensate for the +e options to the C++ front-end.  */
206058997Selan 	n_switches++;
206158997Selan       else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
206258997Selan 	{
206358997Selan 	  register char *p = &argv[i][1];
206458997Selan 	  register int c = *p;
206558997Selan 
206658997Selan 	  switch (c)
206758997Selan 	    {
206858997Selan 	    case 'b':
206958997Selan 	      if (p[1] == 0 && i + 1 == argc)
207058997Selan 		fatal ("argument to `-b' is missing");
207158997Selan 	      if (p[1] == 0)
207258997Selan 		spec_machine = argv[++i];
207358997Selan 	      else
207458997Selan 		spec_machine = p + 1;
207558997Selan 	      break;
207658997Selan 
207758997Selan 	    case 'B':
207858997Selan 	      {
207958997Selan 		int *temp = (int *) xmalloc (sizeof (int));
208058997Selan 		char *value;
208158997Selan 		if (p[1] == 0 && i + 1 == argc)
208258997Selan 		  fatal ("argument to `-B' is missing");
208358997Selan 		if (p[1] == 0)
208458997Selan 		  value = argv[++i];
208558997Selan 		else
208658997Selan 		  value = p + 1;
208758997Selan 		add_prefix (&exec_prefix, value, 1, 0, temp);
208858997Selan 		add_prefix (&startfile_prefix, value, 1, 0, temp);
208958997Selan 	      }
209058997Selan 	      break;
209158997Selan 
209258997Selan 	    case 'v':	/* Print our subcommands and print versions.  */
209358997Selan 	      n_switches++;
209458997Selan 	      /* If they do anything other than exactly `-v', don't set
209558997Selan 		 verbose_flag; rather, continue on to give the error.  */
209658997Selan 	      if (p[1] != 0)
209758997Selan 		break;
209858997Selan 	      verbose_flag++;
209958997Selan 	      break;
210058997Selan 
210158997Selan 	    case 'V':
210258997Selan 	      if (p[1] == 0 && i + 1 == argc)
210358997Selan 		fatal ("argument to `-V' is missing");
210458997Selan 	      if (p[1] == 0)
210558997Selan 		spec_version = argv[++i];
210658997Selan 	      else
210758997Selan 		spec_version = p + 1;
210858997Selan 	      break;
210958997Selan 
211058997Selan 	    case 's':
211158997Selan 	      if (!strcmp (p, "save-temps"))
211258997Selan 		{
211358997Selan 		  save_temps_flag = 1;
211458997Selan 		  n_switches++;
211558997Selan 		  break;
211658997Selan 		}
211758997Selan 	    default:
211858997Selan 	      n_switches++;
211958997Selan 
212058997Selan 	      if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
212158997Selan 		i += SWITCH_TAKES_ARG (c) - (p[1] != 0);
212258997Selan 	      else if (WORD_SWITCH_TAKES_ARG (p))
212358997Selan 		i += WORD_SWITCH_TAKES_ARG (p);
212458997Selan 	    }
212558997Selan 	}
212658997Selan       else
212758997Selan 	n_infiles++;
212858997Selan     }
212958997Selan 
213058997Selan   /* Set up the search paths before we go looking for config files.  */
213158997Selan 
213258997Selan   /* These come before the md prefixes so that we will find gcc's subcommands
213358997Selan      (such as cpp) rather than those of the host system.  */
213458997Selan   /* Use 2 as fourth arg meaning try just the machine as a suffix,
213558997Selan      as well as trying the machine and the version.  */
213658997Selan   add_prefix (&exec_prefix, standard_exec_prefix, 0, 2, NULL_PTR);
213758997Selan   add_prefix (&exec_prefix, standard_exec_prefix_1, 0, 2, NULL_PTR);
213858997Selan 
213958997Selan   add_prefix (&startfile_prefix, standard_exec_prefix, 0, 1, NULL_PTR);
214058997Selan   add_prefix (&startfile_prefix, standard_exec_prefix_1, 0, 1, NULL_PTR);
214158997Selan 
214258997Selan   /* More prefixes are enabled in main, after we read the specs file
214358997Selan      and determine whether this is cross-compilation or not.  */
214458997Selan 
214558997Selan 
214658997Selan   /* Then create the space for the vectors and scan again.  */
214758997Selan 
214858997Selan   switches = ((struct switchstr *)
214958997Selan 	      xmalloc ((n_switches + 1) * sizeof (struct switchstr)));
215058997Selan   infiles = (struct infile *) xmalloc ((n_infiles + 1) * sizeof (struct infile));
215158997Selan   n_switches = 0;
215258997Selan   n_infiles = 0;
215358997Selan   last_language_n_infiles = -1;
215458997Selan 
215558997Selan   /* This, time, copy the text of each switch and store a pointer
215658997Selan      to the copy in the vector of switches.
215758997Selan      Store all the infiles in their vector.  */
215858997Selan 
215958997Selan   for (i = 1; i < argc; i++)
216058997Selan     {
216158997Selan       /* Just skip the switches that were handled by the preceding loop.  */
216258997Selan       if (!strcmp (argv[i], "-Xlinker"))
216358997Selan 	i++;
216458997Selan       else if (! strncmp (argv[i], "-Wl,", 4))
216558997Selan 	;
216658997Selan       else if (! strncmp (argv[i], "-Wa,", 4))
216758997Selan 	;
216858997Selan       else if (! strcmp (argv[i], "-print-libgcc-file-name"))
216958997Selan 	;
217058997Selan       else if (argv[i][0] == '+' && argv[i][1] == 'e')
217158997Selan 	{
217258997Selan 	  /* Compensate for the +e options to the C++ front-end;
217358997Selan 	     they're there simply for cfront call-compatability.  We do
217458997Selan 	     some magic in default_compilers to pass them down properly.
217558997Selan 	     Note we deliberately start at the `+' here, to avoid passing
217658997Selan 	     -e0 or -e1 down into the linker.  */
217758997Selan 	  switches[n_switches].part1 = &argv[i][0];
217858997Selan 	  switches[n_switches].args = 0;
217958997Selan 	  switches[n_switches].valid = 0;
218058997Selan 	  n_switches++;
218158997Selan 	}
218258997Selan       else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
218358997Selan 	{
218458997Selan 	  register char *p = &argv[i][1];
218558997Selan 	  register int c = *p;
218658997Selan 
218758997Selan 	  if (c == 'B' || c == 'b' || c == 'V')
218858997Selan 	    {
218958997Selan 	      /* Skip a separate arg, if any.  */
219058997Selan 	      if (p[1] == 0)
219158997Selan 		i++;
219258997Selan 	      continue;
219358997Selan 	    }
219458997Selan 	  if (c == 'x')
219558997Selan 	    {
219658997Selan 	      if (p[1] == 0 && i + 1 == argc)
219758997Selan 		fatal ("argument to `-x' is missing");
219858997Selan 	      if (p[1] == 0)
219958997Selan 		spec_lang = argv[++i];
220058997Selan 	      else
220158997Selan 		spec_lang = p + 1;
220258997Selan 	      if (! strcmp (spec_lang, "none"))
220358997Selan 		/* Suppress the warning if -xnone comes after the last input file,
220458997Selan 		   because alternate command interfaces like g++ might find it
220558997Selan 		   useful to place -xnone after each input file.  */
220658997Selan 		spec_lang = 0;
220758997Selan 	      else
220858997Selan 		last_language_n_infiles = n_infiles;
220958997Selan 	      continue;
221058997Selan 	    }
221158997Selan 	  switches[n_switches].part1 = p;
221258997Selan 	  /* Deal with option arguments in separate argv elements.  */
221358997Selan 	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
221458997Selan 	      || WORD_SWITCH_TAKES_ARG (p)) {
221558997Selan 	    int j = 0;
221658997Selan 	    int n_args = WORD_SWITCH_TAKES_ARG (p);
221758997Selan 
221858997Selan 	    if (n_args == 0) {
221958997Selan 	      /* Count only the option arguments in separate argv elements.  */
222058997Selan 	      n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
222158997Selan 	    }
222258997Selan 	    if (i + n_args >= argc)
222358997Selan 	      fatal ("argument to `-%s' is missing", p);
222458997Selan 	    switches[n_switches].args
222558997Selan 	      = (char **) xmalloc ((n_args + 1) * sizeof (char *));
222658997Selan 	    while (j < n_args)
222758997Selan 	      switches[n_switches].args[j++] = argv[++i];
222858997Selan 	    /* Null-terminate the vector.  */
222958997Selan 	    switches[n_switches].args[j] = 0;
223058997Selan 	  } else if (*switches_need_spaces != 0 && (c == 'o' || c == 'L')) {
223158997Selan 	    /* On some systems, ld cannot handle -o or -L without space.
223258997Selan 	       So split the -o or -L from its argument.  */
223358997Selan 	    switches[n_switches].part1 = (c == 'o' ? "o" : "L");
223458997Selan 	    switches[n_switches].args = (char **) xmalloc (2 * sizeof (char *));
223558997Selan 	    switches[n_switches].args[0] = xmalloc (strlen (p));
223658997Selan 	    strcpy (switches[n_switches].args[0], &p[1]);
223758997Selan 	    switches[n_switches].args[1] = 0;
223858997Selan 	  } else
223958997Selan 	    switches[n_switches].args = 0;
224058997Selan 	  switches[n_switches].valid = 0;
224158997Selan 	  /* This is always valid, since gcc.c itself understands it.  */
224258997Selan 	  if (!strcmp (p, "save-temps"))
224358997Selan 	    switches[n_switches].valid = 1;
224458997Selan 	  n_switches++;
224558997Selan 	}
224658997Selan       else
224758997Selan 	{
224858997Selan 	  infiles[n_infiles].language = spec_lang;
224958997Selan 	  infiles[n_infiles++].name = argv[i];
225058997Selan 	}
225158997Selan     }
225258997Selan 
225358997Selan   if (n_infiles == last_language_n_infiles)
225458997Selan     error ("Warning: `-x %s' after last input file has no effect", spec_lang);
225558997Selan 
225658997Selan   switches[n_switches].part1 = 0;
225758997Selan   infiles[n_infiles].name = 0;
225858997Selan 
225958997Selan   /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
226058997Selan   if (gcc_exec_prefix)
226158997Selan     {
226258997Selan       temp = (char *) xmalloc (strlen (gcc_exec_prefix) + strlen (spec_version)
226358997Selan 			       + strlen (spec_machine) + 3);
226458997Selan       strcpy (temp, gcc_exec_prefix);
226558997Selan       strcat (temp, spec_machine);
226658997Selan       strcat (temp, "/");
226758997Selan       strcat (temp, spec_version);
226858997Selan       strcat (temp, "/");
226958997Selan       gcc_exec_prefix = temp;
227058997Selan     }
227158997Selan }
227258997Selan 
227358997Selan /* Process a spec string, accumulating and running commands.  */
227458997Selan 
227558997Selan /* These variables describe the input file name.
227658997Selan    input_file_number is the index on outfiles of this file,
227758997Selan    so that the output file name can be stored for later use by %o.
227858997Selan    input_basename is the start of the part of the input file
227958997Selan    sans all directory names, and basename_length is the number
228058997Selan    of characters starting there excluding the suffix .c or whatever.  */
228158997Selan 
228258997Selan static char *input_filename;
228358997Selan static int input_file_number;
228458997Selan static int input_filename_length;
228558997Selan static int basename_length;
228658997Selan static char *input_basename;
228758997Selan static char *input_suffix;
228858997Selan 
228958997Selan /* These are variables used within do_spec and do_spec_1.  */
229058997Selan 
229158997Selan /* Nonzero if an arg has been started and not yet terminated
229258997Selan    (with space, tab or newline).  */
229358997Selan static int arg_going;
229458997Selan 
229558997Selan /* Nonzero means %d or %g has been seen; the next arg to be terminated
229658997Selan    is a temporary file name.  */
229758997Selan static int delete_this_arg;
229858997Selan 
229958997Selan /* Nonzero means %w has been seen; the next arg to be terminated
230058997Selan    is the output file name of this compilation.  */
230158997Selan static int this_is_output_file;
230258997Selan 
230358997Selan /* Nonzero means %s has been seen; the next arg to be terminated
230458997Selan    is the name of a library file and we should try the standard
230558997Selan    search dirs for it.  */
230658997Selan static int this_is_library_file;
230758997Selan 
230858997Selan /* Process the spec SPEC and run the commands specified therein.
230958997Selan    Returns 0 if the spec is successfully processed; -1 if failed.  */
231058997Selan 
231158997Selan static int
do_spec(spec)231258997Selan do_spec (spec)
231358997Selan      char *spec;
231458997Selan {
231558997Selan   int value;
231658997Selan 
231758997Selan   clear_args ();
231858997Selan   arg_going = 0;
231958997Selan   delete_this_arg = 0;
232058997Selan   this_is_output_file = 0;
232158997Selan   this_is_library_file = 0;
232258997Selan 
232358997Selan   value = do_spec_1 (spec, 0, NULL_PTR);
232458997Selan 
232558997Selan   /* Force out any unfinished command.
232658997Selan      If -pipe, this forces out the last command if it ended in `|'.  */
232758997Selan   if (value == 0)
232858997Selan     {
232958997Selan       if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
233058997Selan 	argbuf_index--;
233158997Selan 
233258997Selan       if (argbuf_index > 0)
233358997Selan 	value = execute ();
233458997Selan     }
233558997Selan 
233658997Selan   return value;
233758997Selan }
233858997Selan 
233958997Selan /* Process the sub-spec SPEC as a portion of a larger spec.
234058997Selan    This is like processing a whole spec except that we do
234158997Selan    not initialize at the beginning and we do not supply a
234258997Selan    newline by default at the end.
234358997Selan    INSWITCH nonzero means don't process %-sequences in SPEC;
234458997Selan    in this case, % is treated as an ordinary character.
234558997Selan    This is used while substituting switches.
234658997Selan    INSWITCH nonzero also causes SPC not to terminate an argument.
234758997Selan 
234858997Selan    Value is zero unless a line was finished
234958997Selan    and the command on that line reported an error.  */
235058997Selan 
235158997Selan static int
do_spec_1(spec,inswitch,soft_matched_part)235258997Selan do_spec_1 (spec, inswitch, soft_matched_part)
235358997Selan      char *spec;
235458997Selan      int inswitch;
235558997Selan      char *soft_matched_part;
235658997Selan {
235758997Selan   register char *p = spec;
235858997Selan   register int c;
235958997Selan   int i;
236058997Selan   char *string;
236158997Selan 
236258997Selan   while (c = *p++)
236358997Selan     /* If substituting a switch, treat all chars like letters.
236458997Selan        Otherwise, NL, SPC, TAB and % are special.  */
236558997Selan     switch (inswitch ? 'a' : c)
236658997Selan       {
236758997Selan       case '\n':
236858997Selan 	/* End of line: finish any pending argument,
236958997Selan 	   then run the pending command if one has been started.  */
237058997Selan 	if (arg_going)
237158997Selan 	  {
237258997Selan 	    obstack_1grow (&obstack, 0);
237358997Selan 	    string = obstack_finish (&obstack);
237458997Selan 	    if (this_is_library_file)
237558997Selan 	      string = find_file (string);
237658997Selan 	    store_arg (string, delete_this_arg, this_is_output_file);
237758997Selan 	    if (this_is_output_file)
237858997Selan 	      outfiles[input_file_number] = string;
237958997Selan 	  }
238058997Selan 	arg_going = 0;
238158997Selan 
238258997Selan 	if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
238358997Selan 	  {
238458997Selan 	    int i;
238558997Selan 	    for (i = 0; i < n_switches; i++)
238658997Selan 	      if (!strcmp (switches[i].part1, "pipe"))
238758997Selan 		break;
238858997Selan 
238958997Selan 	    /* A `|' before the newline means use a pipe here,
239058997Selan 	       but only if -pipe was specified.
239158997Selan 	       Otherwise, execute now and don't pass the `|' as an arg.  */
239258997Selan 	    if (i < n_switches)
239358997Selan 	      {
239458997Selan 		switches[i].valid = 1;
239558997Selan 		break;
239658997Selan 	      }
239758997Selan 	    else
239858997Selan 	      argbuf_index--;
239958997Selan 	  }
240058997Selan 
240158997Selan 	if (argbuf_index > 0)
240258997Selan 	  {
240358997Selan 	    int value = execute ();
240458997Selan 	    if (value)
240558997Selan 	      return value;
240658997Selan 	  }
240758997Selan 	/* Reinitialize for a new command, and for a new argument.  */
240858997Selan 	clear_args ();
240958997Selan 	arg_going = 0;
241058997Selan 	delete_this_arg = 0;
241158997Selan 	this_is_output_file = 0;
241258997Selan 	this_is_library_file = 0;
241358997Selan 	break;
241458997Selan 
241558997Selan       case '|':
241658997Selan 	/* End any pending argument.  */
241758997Selan 	if (arg_going)
241858997Selan 	  {
241958997Selan 	    obstack_1grow (&obstack, 0);
242058997Selan 	    string = obstack_finish (&obstack);
242158997Selan 	    if (this_is_library_file)
242258997Selan 	      string = find_file (string);
242358997Selan 	    store_arg (string, delete_this_arg, this_is_output_file);
242458997Selan 	    if (this_is_output_file)
242558997Selan 	      outfiles[input_file_number] = string;
242658997Selan 	  }
242758997Selan 
242858997Selan 	/* Use pipe */
242958997Selan 	obstack_1grow (&obstack, c);
243058997Selan 	arg_going = 1;
243158997Selan 	break;
243258997Selan 
243358997Selan       case '\t':
243458997Selan       case ' ':
243558997Selan 	/* Space or tab ends an argument if one is pending.  */
243658997Selan 	if (arg_going)
243758997Selan 	  {
243858997Selan 	    obstack_1grow (&obstack, 0);
243958997Selan 	    string = obstack_finish (&obstack);
244058997Selan 	    if (this_is_library_file)
244158997Selan 	      string = find_file (string);
244258997Selan 	    store_arg (string, delete_this_arg, this_is_output_file);
244358997Selan 	    if (this_is_output_file)
244458997Selan 	      outfiles[input_file_number] = string;
244558997Selan 	  }
244658997Selan 	/* Reinitialize for a new argument.  */
244758997Selan 	arg_going = 0;
244858997Selan 	delete_this_arg = 0;
244958997Selan 	this_is_output_file = 0;
245058997Selan 	this_is_library_file = 0;
245158997Selan 	break;
245258997Selan 
245358997Selan       case '%':
245458997Selan 	switch (c = *p++)
245558997Selan 	  {
245658997Selan 	  case 0:
245758997Selan 	    fatal ("Invalid specification!  Bug in cc.");
245858997Selan 
245958997Selan 	  case 'b':
246058997Selan 	    obstack_grow (&obstack, input_basename, basename_length);
246158997Selan 	    arg_going = 1;
246258997Selan 	    break;
246358997Selan 
246458997Selan 	  case 'd':
246558997Selan 	    delete_this_arg = 2;
246658997Selan 	    break;
246758997Selan 
246858997Selan 	  /* Dump out the directories specified with LIBRARY_PATH,
246958997Selan 	     followed by the absolute directories
247058997Selan 	     that we search for startfiles.  */
247158997Selan 	  case 'D':
247258997Selan 	    for (i = 0; i < 2; i++)
247358997Selan 	      {
247458997Selan 		struct prefix_list *pl
247558997Selan 		  = (i == 0 ? library_prefix.plist : startfile_prefix.plist);
247658997Selan 		int bufsize = 100;
247758997Selan 		char *buffer = (char *) xmalloc (bufsize);
247858997Selan 		int idx;
247958997Selan 
248058997Selan 		for (; pl; pl = pl->next)
248158997Selan 		  {
248258997Selan #ifdef RELATIVE_PREFIX_NOT_LINKDIR
248358997Selan 		    /* Used on systems which record the specified -L dirs
248458997Selan 		       and use them to search for dynamic linking.  */
248558997Selan 		    /* Relative directories always come from -B,
248658997Selan 		       and it is better not to use them for searching
248758997Selan 		       at run time.  In particular, stage1 loses  */
248858997Selan 		    if (pl->prefix[0] != '/')
248958997Selan 		      continue;
249058997Selan #endif
249158997Selan 		    if (machine_suffix)
249258997Selan 		      {
249358997Selan 			if (is_linker_dir (pl->prefix, machine_suffix))
249458997Selan 			  {
249558997Selan 			    do_spec_1 ("-L", 0, NULL_PTR);
249658997Selan #ifdef SPACE_AFTER_L_OPTION
249758997Selan 			    do_spec_1 (" ", 0, NULL_PTR);
249858997Selan #endif
249958997Selan 			    do_spec_1 (pl->prefix, 1, NULL_PTR);
250058997Selan 			    /* Remove slash from machine_suffix.  */
250158997Selan 			    if (strlen (machine_suffix) >= bufsize)
250258997Selan 			      bufsize = strlen (machine_suffix) * 2 + 1;
250358997Selan 			    buffer = (char *) xrealloc (buffer, bufsize);
250458997Selan 			    strcpy (buffer, machine_suffix);
250558997Selan 			    idx = strlen (buffer);
250658997Selan 			    if (buffer[idx - 1] == '/')
250758997Selan 			      buffer[idx - 1] = 0;
250858997Selan 			    do_spec_1 (buffer, 1, NULL_PTR);
250958997Selan 			    /* Make this a separate argument.  */
251058997Selan 			    do_spec_1 (" ", 0, NULL_PTR);
251158997Selan 			  }
251258997Selan 		      }
251358997Selan 		    if (!pl->require_machine_suffix)
251458997Selan 		      {
251558997Selan 			if (is_linker_dir (pl->prefix, ""))
251658997Selan 			  {
251758997Selan 			    do_spec_1 ("-L", 0, NULL_PTR);
251858997Selan #ifdef SPACE_AFTER_L_OPTION
251958997Selan 			    do_spec_1 (" ", 0, NULL_PTR);
252058997Selan #endif
252158997Selan 			    /* Remove slash from pl->prefix.  */
252258997Selan 			    if (strlen (pl->prefix) >= bufsize)
252358997Selan 			      bufsize = strlen (pl->prefix) * 2 + 1;
252458997Selan 			    buffer = (char *) xrealloc (buffer, bufsize);
252558997Selan 			    strcpy (buffer, pl->prefix);
252658997Selan 			    idx = strlen (buffer);
252758997Selan 			    if (buffer[idx - 1] == '/')
252858997Selan 			      buffer[idx - 1] = 0;
252958997Selan 			    do_spec_1 (buffer, 1, NULL_PTR);
253058997Selan 			    /* Make this a separate argument.  */
253158997Selan 			    do_spec_1 (" ", 0, NULL_PTR);
253258997Selan 			  }
253358997Selan 		      }
253458997Selan 		  }
253558997Selan 		free (buffer);
253658997Selan 	      }
253758997Selan 	    break;
253858997Selan 
253958997Selan 	  case 'e':
254058997Selan 	    /* {...:%efoo} means report an error with `foo' as error message
254158997Selan 	       and don't execute any more commands for this file.  */
254258997Selan 	    {
254358997Selan 	      char *q = p;
254458997Selan 	      char *buf;
254558997Selan 	      while (*p != 0 && *p != '\n') p++;
254658997Selan 	      buf = (char *) alloca (p - q + 1);
254758997Selan 	      strncpy (buf, q, p - q);
254858997Selan 	      buf[p - q] = 0;
254958997Selan 	      error ("%s", buf);
255058997Selan 	      return -1;
255158997Selan 	    }
255258997Selan 	    break;
255358997Selan 
255458997Selan 	  case 'g':
255558997Selan 	  case 'u':
255658997Selan 	  case 'U':
255758997Selan 	    if (save_temps_flag)
255858997Selan 	      obstack_grow (&obstack, input_basename, basename_length);
255958997Selan 	    else
256058997Selan 	      {
256158997Selan #ifdef MKTEMP_EACH_FILE
256258997Selan 		/* ??? This has a problem: the total number of
256358997Selan 		   values mktemp can return is limited.
256458997Selan 		   That matters for the names of object files.
256558997Selan 		   In 2.4, do something about that.  */
256658997Selan 		struct temp_name *t;
256758997Selan 		char *suffix = p;
256858997Selan 		while (*p == '.' || isalpha (*p))
256958997Selan 		  p++;
257058997Selan 
257158997Selan 		/* See if we already have an association of %g/%u/%U and
257258997Selan 		   suffix.  */
257358997Selan 		for (t = temp_names; t; t = t->next)
257458997Selan 		  if (t->length == p - suffix
257558997Selan 		      && strncmp (t->suffix, suffix, p - suffix) == 0
257658997Selan 		      && t->unique == (c != 'g'))
257758997Selan 		    break;
257858997Selan 
257958997Selan 		/* Make a new association if needed.  %u requires one.  */
258058997Selan 		if (t == 0 || c == 'u')
258158997Selan 		  {
258258997Selan 		    if (t == 0)
258358997Selan 		      {
258458997Selan 			t = (struct temp_name *) xmalloc (sizeof (struct temp_name));
258558997Selan 			t->next = temp_names;
258658997Selan 			temp_names = t;
258758997Selan 		      }
258858997Selan 		    t->length = p - suffix;
258958997Selan 		    t->suffix = save_string (suffix, p - suffix);
259058997Selan 		    t->unique = (c != 'g');
259158997Selan 		    choose_temp_base ();
259258997Selan 		    t->filename = temp_filename;
259358997Selan 		    t->filename_length = temp_filename_length;
259458997Selan 		  }
259558997Selan 
259658997Selan 		obstack_grow (&obstack, t->filename, t->filename_length);
259758997Selan 		delete_this_arg = 1;
259858997Selan #else
259958997Selan 		obstack_grow (&obstack, temp_filename, temp_filename_length);
260058997Selan 		if (c == 'u' || c == 'U')
260158997Selan 		  {
260258997Selan 		    static int unique;
260358997Selan 		    char buff[9];
260458997Selan 		    if (c == 'u')
260558997Selan 		      unique++;
260658997Selan 		    sprintf (buff, "%d", unique);
260758997Selan 		    obstack_grow (&obstack, buff, strlen (buff));
260858997Selan 		  }
260958997Selan #endif
261058997Selan 		delete_this_arg = 1;
261158997Selan 	      }
261258997Selan 	    arg_going = 1;
261358997Selan 	    break;
261458997Selan 
261558997Selan 	  case 'i':
261658997Selan 	    obstack_grow (&obstack, input_filename, input_filename_length);
261758997Selan 	    arg_going = 1;
261858997Selan 	    break;
261958997Selan 
262058997Selan 	  case 'I':
262158997Selan 	    if (gcc_exec_prefix)
262258997Selan 	      {
262358997Selan 		do_spec_1 ("-iprefix", 1, NULL_PTR);
262458997Selan 		/* Make this a separate argument.  */
262558997Selan 		do_spec_1 (" ", 0, NULL_PTR);
262658997Selan 		do_spec_1 (gcc_exec_prefix, 1, NULL_PTR);
262758997Selan 		do_spec_1 (" ", 0, NULL_PTR);
262858997Selan 	      }
262958997Selan 	    break;
263058997Selan 
263158997Selan 	  case 'o':
263258997Selan 	    {
263358997Selan 	      register int f;
263458997Selan 	      for (f = 0; f < n_infiles; f++)
263558997Selan 		store_arg (outfiles[f], 0, 0);
263658997Selan 	    }
263758997Selan 	    break;
263858997Selan 
263958997Selan 	  case 's':
264058997Selan 	    this_is_library_file = 1;
264158997Selan 	    break;
264258997Selan 
264358997Selan 	  case 'w':
264458997Selan 	    this_is_output_file = 1;
264558997Selan 	    break;
264658997Selan 
264758997Selan 	  case 'W':
264858997Selan 	    {
264958997Selan 	      int index = argbuf_index;
265058997Selan 	      /* Handle the {...} following the %W.  */
265158997Selan 	      if (*p != '{')
265258997Selan 		abort ();
265358997Selan 	      p = handle_braces (p + 1);
265458997Selan 	      if (p == 0)
265558997Selan 		return -1;
265658997Selan 	      /* If any args were output, mark the last one for deletion
265758997Selan 		 on failure.  */
265858997Selan 	      if (argbuf_index != index)
265958997Selan 		record_temp_file (argbuf[argbuf_index - 1], 0, 1);
266058997Selan 	      break;
266158997Selan 	    }
266258997Selan 
266358997Selan 	  /* %x{OPTION} records OPTION for %X to output.  */
266458997Selan 	  case 'x':
266558997Selan 	    {
266658997Selan 	      char *p1 = p;
266758997Selan 	      char *string;
266858997Selan 
266958997Selan 	      /* Skip past the option value and make a copy.  */
267058997Selan 	      if (*p != '{')
267158997Selan 		abort ();
267258997Selan 	      while (*p++ != '}')
267358997Selan 		;
267458997Selan 	      string = save_string (p1 + 1, p - p1 - 2);
267558997Selan 
267658997Selan 	      /* See if we already recorded this option.  */
267758997Selan 	      for (i = 0; i < n_linker_options; i++)
267858997Selan 		if (! strcmp (string, linker_options[i]))
267958997Selan 		  {
268058997Selan 		    free (string);
268158997Selan 		    return 0;
268258997Selan 		  }
268358997Selan 
268458997Selan 	      /* This option is new; add it.  */
268558997Selan 	      n_linker_options++;
268658997Selan 	      if (!linker_options)
268758997Selan 		linker_options
268858997Selan 		  = (char **) xmalloc (n_linker_options * sizeof (char **));
268958997Selan 	      else
269058997Selan 		linker_options
269158997Selan 		  = (char **) xrealloc (linker_options,
269258997Selan 					n_linker_options * sizeof (char **));
269358997Selan 
269458997Selan 	      linker_options[n_linker_options - 1] = string;
269558997Selan 	    }
269658997Selan 	    break;
269758997Selan 
269858997Selan 	  /* Dump out the options accumulated previously using %x,
269958997Selan 	     -Xlinker and -Wl,.  */
270058997Selan 	  case 'X':
270158997Selan 	    for (i = 0; i < n_linker_options; i++)
270258997Selan 	      {
270358997Selan 		do_spec_1 (linker_options[i], 1, NULL_PTR);
270458997Selan 		/* Make each accumulated option a separate argument.  */
270558997Selan 		do_spec_1 (" ", 0, NULL_PTR);
270658997Selan 	      }
270758997Selan 	    break;
270858997Selan 
270958997Selan 	  /* Dump out the options accumulated previously using -Wa,.  */
271058997Selan 	  case 'Y':
271158997Selan 	    for (i = 0; i < n_assembler_options; i++)
271258997Selan 	      {
271358997Selan 		do_spec_1 (assembler_options[i], 1, NULL_PTR);
271458997Selan 		/* Make each accumulated option a separate argument.  */
271558997Selan 		do_spec_1 (" ", 0, NULL_PTR);
271658997Selan 	      }
271758997Selan 	    break;
271858997Selan 
271958997Selan 	    /* Here are digits and numbers that just process
272058997Selan 	       a certain constant string as a spec.
272158997Selan 	    /* Here are digits and numbers that just process
272258997Selan 	       a certain constant string as a spec.  */
272358997Selan 
272458997Selan 	  case '1':
272558997Selan 	    do_spec_1 (cc1_spec, 0, NULL_PTR);
272658997Selan 	    break;
272758997Selan 
272858997Selan 	  case '2':
272958997Selan 	    do_spec_1 (cc1plus_spec, 0, NULL_PTR);
273058997Selan 	    break;
273158997Selan 
273258997Selan 	  case 'a':
273358997Selan 	    do_spec_1 (asm_spec, 0, NULL_PTR);
273458997Selan 	    break;
273558997Selan 
273658997Selan 	  case 'A':
273758997Selan 	    do_spec_1 (asm_final_spec, 0, NULL_PTR);
273858997Selan 	    break;
273958997Selan 
274058997Selan 	  case 'c':
274158997Selan 	    do_spec_1 (signed_char_spec, 0, NULL_PTR);
274258997Selan 	    break;
274358997Selan 
274458997Selan 	  case 'C':
274558997Selan 	    do_spec_1 (cpp_spec, 0, NULL_PTR);
274658997Selan 	    break;
274758997Selan 
274858997Selan 	  case 'E':
274958997Selan 	    do_spec_1 (endfile_spec, 0, NULL_PTR);
275058997Selan 	    break;
275158997Selan 
275258997Selan 	  case 'l':
275358997Selan 	    do_spec_1 (link_spec, 0, NULL_PTR);
275458997Selan 	    break;
275558997Selan 
275658997Selan 	  case 'L':
275758997Selan 	    do_spec_1 (lib_spec, 0, NULL_PTR);
275858997Selan 	    break;
275958997Selan 
276058997Selan 	  case 'p':
276158997Selan 	    {
276258997Selan 	      char *x = (char *) alloca (strlen (cpp_predefines) + 1);
276358997Selan 	      char *buf = x;
276458997Selan 	      char *y;
276558997Selan 
276658997Selan 	      /* Copy all of the -D options in CPP_PREDEFINES into BUF.  */
276758997Selan 	      y = cpp_predefines;
276858997Selan 	      while (*y != 0)
276958997Selan 		{
277058997Selan 		  if (! strncmp (y, "-D", 2))
277158997Selan 		    /* Copy the whole option.  */
277258997Selan 		    while (*y && *y != ' ' && *y != '\t')
277358997Selan 		      *x++ = *y++;
277458997Selan 		  else if (*y == ' ' || *y == '\t')
277558997Selan 		    /* Copy whitespace to the result.  */
277658997Selan 		    *x++ = *y++;
277758997Selan 		  /* Don't copy other options.  */
277858997Selan 		  else
277958997Selan 		    y++;
278058997Selan 		}
278158997Selan 
278258997Selan 	      *x = 0;
278358997Selan 
278458997Selan 	      do_spec_1 (buf, 0, NULL_PTR);
278558997Selan 	    }
278658997Selan 	    break;
278758997Selan 
278858997Selan 	  case 'P':
278958997Selan 	    {
279058997Selan 	      char *x = (char *) alloca (strlen (cpp_predefines) * 4 + 1);
279158997Selan 	      char *buf = x;
279258997Selan 	      char *y;
279358997Selan 
279458997Selan 	      /* Copy all of CPP_PREDEFINES into BUF,
279558997Selan 		 but put __ after every -D and at the end of each arg.  */
279658997Selan 	      y = cpp_predefines;
279758997Selan 	      while (*y != 0)
279858997Selan 		{
279958997Selan 		  if (! strncmp (y, "-D", 2))
280058997Selan 		    {
280158997Selan 		      int flag = 0;
280258997Selan 
280358997Selan 		      *x++ = *y++;
280458997Selan 		      *x++ = *y++;
280558997Selan 
280658997Selan 		      if (strncmp (y, "__", 2))
280758997Selan 		        {
280858997Selan 			  /* Stick __ at front of macro name.  */
280958997Selan 			  *x++ = '_';
281058997Selan 			  *x++ = '_';
281158997Selan 			  /* Arrange to stick __ at the end as well.  */
281258997Selan 			  flag = 1;
281358997Selan 			}
281458997Selan 
281558997Selan 		      /* Copy the macro name.  */
281658997Selan 		      while (*y && *y != '=' && *y != ' ' && *y != '\t')
281758997Selan 			*x++ = *y++;
281858997Selan 
281958997Selan 		      if (flag)
282058997Selan 		        {
282158997Selan 			  *x++ = '_';
282258997Selan 			  *x++ = '_';
282358997Selan 			}
282458997Selan 
282558997Selan 		      /* Copy the value given, if any.  */
282658997Selan 		      while (*y && *y != ' ' && *y != '\t')
282758997Selan 			*x++ = *y++;
282858997Selan 		    }
282958997Selan 		  else if (*y == ' ' || *y == '\t')
283058997Selan 		    /* Copy whitespace to the result.  */
283158997Selan 		    *x++ = *y++;
283258997Selan 		  /* Don't copy -A options  */
283358997Selan 		  else
283458997Selan 		    y++;
283558997Selan 		}
283658997Selan 	      *x++ = ' ';
283758997Selan 
283858997Selan 	      /* Copy all of CPP_PREDEFINES into BUF,
283958997Selan 		 but put __ after every -D.  */
284058997Selan 	      y = cpp_predefines;
284158997Selan 	      while (*y != 0)
284258997Selan 		{
284358997Selan 		  if (! strncmp (y, "-D", 2))
284458997Selan 		    {
284558997Selan 		      *x++ = *y++;
284658997Selan 		      *x++ = *y++;
284758997Selan 
284858997Selan 		      if (strncmp (y, "__", 2))
284958997Selan 		        {
285058997Selan 			  /* Stick __ at front of macro name.  */
285158997Selan 			  *x++ = '_';
285258997Selan 			  *x++ = '_';
285358997Selan 			}
285458997Selan 
285558997Selan 		      /* Copy the macro name.  */
285658997Selan 		      while (*y && *y != '=' && *y != ' ' && *y != '\t')
285758997Selan 			*x++ = *y++;
285858997Selan 
285958997Selan 		      /* Copy the value given, if any.  */
286058997Selan 		      while (*y && *y != ' ' && *y != '\t')
286158997Selan 			*x++ = *y++;
286258997Selan 		    }
286358997Selan 		  else if (*y == ' ' || *y == '\t')
286458997Selan 		    /* Copy whitespace to the result.  */
286558997Selan 		    *x++ = *y++;
286658997Selan 		  /* Don't copy -A options  */
286758997Selan 		  else
286858997Selan 		    y++;
286958997Selan 		}
287058997Selan 	      *x++ = ' ';
287158997Selan 
287258997Selan 	      /* Copy all of the -A options in CPP_PREDEFINES into BUF.  */
287358997Selan 	      y = cpp_predefines;
287458997Selan 	      while (*y != 0)
287558997Selan 		{
287658997Selan 		  if (! strncmp (y, "-A", 2))
287758997Selan 		    /* Copy the whole option.  */
287858997Selan 		    while (*y && *y != ' ' && *y != '\t')
287958997Selan 		      *x++ = *y++;
288058997Selan 		  else if (*y == ' ' || *y == '\t')
288158997Selan 		    /* Copy whitespace to the result.  */
288258997Selan 		    *x++ = *y++;
288358997Selan 		  /* Don't copy other options.  */
288458997Selan 		  else
288558997Selan 		    y++;
288658997Selan 		}
288758997Selan 
288858997Selan 	      *x = 0;
288958997Selan 
289058997Selan 	      do_spec_1 (buf, 0, NULL_PTR);
289158997Selan 	    }
289258997Selan 	    break;
289358997Selan 
289458997Selan 	  case 'S':
289558997Selan 	    do_spec_1 (startfile_spec, 0, NULL_PTR);
289658997Selan 	    break;
289758997Selan 
289858997Selan 	    /* Here we define characters other than letters and digits.  */
289958997Selan 
290058997Selan 	  case '{':
290158997Selan 	    p = handle_braces (p);
290258997Selan 	    if (p == 0)
290358997Selan 	      return -1;
290458997Selan 	    break;
290558997Selan 
290658997Selan 	  case '%':
290758997Selan 	    obstack_1grow (&obstack, '%');
290858997Selan 	    break;
290958997Selan 
291058997Selan 	  case '*':
291158997Selan 	    do_spec_1 (soft_matched_part, 1, NULL_PTR);
291258997Selan 	    do_spec_1 (" ", 0, NULL_PTR);
291358997Selan 	    break;
291458997Selan 
291558997Selan 	    /* Process a string found as the value of a spec given by name.
291658997Selan 	       This feature allows individual machine descriptions
291758997Selan 	       to add and use their own specs.
291858997Selan 	       %[...] modifies -D options the way %P does;
291958997Selan 	       %(...) uses the spec unmodified.  */
292058997Selan 	  case '(':
292158997Selan 	  case '[':
292258997Selan 	    {
292358997Selan 	      char *name = p;
292458997Selan 	      struct spec_list *sl;
292558997Selan 	      int len;
292658997Selan 
292758997Selan 	      /* The string after the S/P is the name of a spec that is to be
292858997Selan 		 processed. */
292958997Selan 	      while (*p && *p != ')' && *p != ']')
293058997Selan 		p++;
293158997Selan 
293258997Selan 	      /* See if it's in the list */
293358997Selan 	      for (len = p - name, sl = specs; sl; sl = sl->next)
293458997Selan 		if (strncmp (sl->name, name, len) == 0 && !sl->name[len])
293558997Selan 		  {
293658997Selan 		    name = sl->spec;
293758997Selan 		    break;
293858997Selan 		  }
293958997Selan 
294058997Selan 	      if (sl)
294158997Selan 		{
294258997Selan 		  if (c == '(')
294358997Selan 		    do_spec_1 (name, 0, NULL_PTR);
294458997Selan 		  else
294558997Selan 		    {
294658997Selan 		      char *x = (char *) alloca (strlen (name) * 2 + 1);
294758997Selan 		      char *buf = x;
294858997Selan 		      char *y = name;
294958997Selan 
295058997Selan 		      /* Copy all of NAME into BUF, but put __ after
295158997Selan 			 every -D and at the end of each arg,  */
295258997Selan 		      while (1)
295358997Selan 			{
295458997Selan 			  if (! strncmp (y, "-D", 2))
295558997Selan 			    {
295658997Selan 			      *x++ = '-';
295758997Selan 			      *x++ = 'D';
295858997Selan 			      *x++ = '_';
295958997Selan 			      *x++ = '_';
296058997Selan 			      y += 2;
296158997Selan 			    }
296258997Selan 			  else if (*y == ' ' || *y == 0)
296358997Selan 			    {
296458997Selan 			      *x++ = '_';
296558997Selan 			      *x++ = '_';
296658997Selan 			      if (*y == 0)
296758997Selan 				break;
296858997Selan 			      else
296958997Selan 				*x++ = *y++;
297058997Selan 			    }
297158997Selan 			  else
297258997Selan 			    *x++ = *y++;
297358997Selan 			}
297458997Selan 		      *x = 0;
297558997Selan 
297658997Selan 		      do_spec_1 (buf, 0, NULL_PTR);
297758997Selan 		    }
297858997Selan 		}
297958997Selan 
298058997Selan 	      /* Discard the closing paren or bracket.  */
298158997Selan 	      if (*p)
298258997Selan 		p++;
298358997Selan 	    }
298458997Selan 	    break;
298558997Selan 
298658997Selan 	  default:
298758997Selan 	    abort ();
298858997Selan 	  }
298958997Selan 	break;
299058997Selan 
299158997Selan       case '\\':
299258997Selan 	/* Backslash: treat next character as ordinary.  */
299358997Selan 	c = *p++;
299458997Selan 
299558997Selan 	/* fall through */
299658997Selan       default:
299758997Selan 	/* Ordinary character: put it into the current argument.  */
299858997Selan 	obstack_1grow (&obstack, c);
299958997Selan 	arg_going = 1;
300058997Selan       }
300158997Selan 
300258997Selan   return 0;		/* End of string */
300358997Selan }
300458997Selan 
300558997Selan /* Return 0 if we call do_spec_1 and that returns -1.  */
300658997Selan 
300758997Selan static char *
handle_braces(p)300858997Selan handle_braces (p)
300958997Selan      register char *p;
301058997Selan {
301158997Selan   register char *q;
301258997Selan   char *filter;
301358997Selan   int pipe = 0;
301458997Selan   int negate = 0;
301558997Selan   int suffix = 0;
301658997Selan 
301758997Selan   if (*p == '|')
301858997Selan     /* A `|' after the open-brace means,
301958997Selan        if the test fails, output a single minus sign rather than nothing.
302058997Selan        This is used in %{|!pipe:...}.  */
302158997Selan     pipe = 1, ++p;
302258997Selan 
302358997Selan   if (*p == '!')
302458997Selan     /* A `!' after the open-brace negates the condition:
302558997Selan        succeed if the specified switch is not present.  */
302658997Selan     negate = 1, ++p;
302758997Selan 
302858997Selan   if (*p == '.')
302958997Selan     /* A `.' after the open-brace means test against the current suffix.  */
303058997Selan     {
303158997Selan       if (pipe)
303258997Selan 	abort ();
303358997Selan 
303458997Selan       suffix = 1;
303558997Selan       ++p;
303658997Selan     }
303758997Selan 
303858997Selan   filter = p;
303958997Selan   while (*p != ':' && *p != '}') p++;
304058997Selan   if (*p != '}')
304158997Selan     {
304258997Selan       register int count = 1;
304358997Selan       q = p + 1;
304458997Selan       while (count > 0)
304558997Selan 	{
304658997Selan 	  if (*q == '{')
304758997Selan 	    count++;
304858997Selan 	  else if (*q == '}')
304958997Selan 	    count--;
305058997Selan 	  else if (*q == 0)
305158997Selan 	    abort ();
305258997Selan 	  q++;
305358997Selan 	}
305458997Selan     }
305558997Selan   else
305658997Selan     q = p + 1;
305758997Selan 
305858997Selan   if (suffix)
305958997Selan     {
306058997Selan       int found = (input_suffix != 0
306158997Selan 		   && strlen (input_suffix) == p - filter
306258997Selan 		   && strncmp (input_suffix, filter, p - filter) == 0);
306358997Selan 
306458997Selan       if (p[0] == '}')
306558997Selan 	abort ();
306658997Selan 
306758997Selan       if (negate != found
306858997Selan 	  && do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
306958997Selan 	return 0;
307058997Selan 
307158997Selan       return q;
307258997Selan     }
307358997Selan   else if (p[-1] == '*' && p[0] == '}')
307458997Selan     {
307558997Selan       /* Substitute all matching switches as separate args.  */
307658997Selan       register int i;
307758997Selan       --p;
307858997Selan       for (i = 0; i < n_switches; i++)
307958997Selan 	if (!strncmp (switches[i].part1, filter, p - filter))
308058997Selan 	  give_switch (i, 0);
308158997Selan     }
308258997Selan   else
308358997Selan     {
308458997Selan       /* Test for presence of the specified switch.  */
308558997Selan       register int i;
308658997Selan       int present = 0;
308758997Selan 
308858997Selan       /* If name specified ends in *, as in {x*:...},
308958997Selan 	 check for %* and handle that case.  */
309058997Selan       if (p[-1] == '*' && !negate)
309158997Selan 	{
309258997Selan 	  int substitution;
309358997Selan 	  char *r = p;
309458997Selan 
309558997Selan 	  /* First see whether we have %*.  */
309658997Selan 	  substitution = 0;
309758997Selan 	  while (r < q)
309858997Selan 	    {
309958997Selan 	      if (*r == '%' && r[1] == '*')
310058997Selan 		substitution = 1;
310158997Selan 	      r++;
310258997Selan 	    }
310358997Selan 	  /* If we do, handle that case.  */
310458997Selan 	  if (substitution)
310558997Selan 	    {
310658997Selan 	      /* Substitute all matching switches as separate args.
310758997Selan 		 But do this by substituting for %*
310858997Selan 		 in the text that follows the colon.  */
310958997Selan 
311058997Selan 	      unsigned hard_match_len = p - filter - 1;
311158997Selan 	      char *string = save_string (p + 1, q - p - 2);
311258997Selan 
311358997Selan 	      for (i = 0; i < n_switches; i++)
311458997Selan 		if (!strncmp (switches[i].part1, filter, hard_match_len))
311558997Selan 		  {
311658997Selan 		    do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
311758997Selan 		    /* Pass any arguments this switch has.  */
311858997Selan 		    give_switch (i, 1);
311958997Selan 		  }
312058997Selan 
312158997Selan 	      return q;
312258997Selan 	    }
312358997Selan 	}
312458997Selan 
312558997Selan       /* If name specified ends in *, as in {x*:...},
312658997Selan 	 check for presence of any switch name starting with x.  */
312758997Selan       if (p[-1] == '*')
312858997Selan 	{
312958997Selan 	  for (i = 0; i < n_switches; i++)
313058997Selan 	    {
313158997Selan 	      unsigned hard_match_len = p - filter - 1;
313258997Selan 
313358997Selan 	      if (!strncmp (switches[i].part1, filter, hard_match_len))
313458997Selan 		{
313558997Selan 		  switches[i].valid = 1;
313658997Selan 		  present = 1;
313758997Selan 		}
313858997Selan 	    }
313958997Selan 	}
314058997Selan       /* Otherwise, check for presence of exact name specified.  */
314158997Selan       else
314258997Selan 	{
314358997Selan 	  for (i = 0; i < n_switches; i++)
314458997Selan 	    {
314558997Selan 	      if (!strncmp (switches[i].part1, filter, p - filter)
314658997Selan 		  && switches[i].part1[p - filter] == 0)
314758997Selan 		{
314858997Selan 		  switches[i].valid = 1;
314958997Selan 		  present = 1;
315058997Selan 		  break;
315158997Selan 		}
315258997Selan 	    }
315358997Selan 	}
315458997Selan 
315558997Selan       /* If it is as desired (present for %{s...}, absent for %{-s...})
315658997Selan 	 then substitute either the switch or the specified
315758997Selan 	 conditional text.  */
315858997Selan       if (present != negate)
315958997Selan 	{
316058997Selan 	  if (*p == '}')
316158997Selan 	    {
316258997Selan 	      give_switch (i, 0);
316358997Selan 	    }
316458997Selan 	  else
316558997Selan 	    {
316658997Selan 	      if (do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
316758997Selan 		return 0;
316858997Selan 	    }
316958997Selan 	}
317058997Selan       else if (pipe)
317158997Selan 	{
317258997Selan 	  /* Here if a %{|...} conditional fails: output a minus sign,
317358997Selan 	     which means "standard output" or "standard input".  */
317458997Selan 	  do_spec_1 ("-", 0, NULL_PTR);
317558997Selan 	}
317658997Selan     }
317758997Selan 
317858997Selan   return q;
317958997Selan }
318058997Selan 
318158997Selan /* Pass a switch to the current accumulating command
318258997Selan    in the same form that we received it.
318358997Selan    SWITCHNUM identifies the switch; it is an index into
318458997Selan    the vector of switches gcc received, which is `switches'.
318558997Selan    This cannot fail since it never finishes a command line.
318658997Selan 
318758997Selan    If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.  */
318858997Selan 
318958997Selan static void
give_switch(switchnum,omit_first_word)319058997Selan give_switch (switchnum, omit_first_word)
319158997Selan      int switchnum;
319258997Selan      int omit_first_word;
319358997Selan {
319458997Selan   if (!omit_first_word)
319558997Selan     {
319658997Selan       do_spec_1 ("-", 0, NULL_PTR);
319758997Selan       do_spec_1 (switches[switchnum].part1, 1, NULL_PTR);
319858997Selan     }
319958997Selan   do_spec_1 (" ", 0, NULL_PTR);
320058997Selan   if (switches[switchnum].args != 0)
320158997Selan     {
320258997Selan       char **p;
320358997Selan       for (p = switches[switchnum].args; *p; p++)
320458997Selan 	{
320558997Selan 	  do_spec_1 (*p, 1, NULL_PTR);
320658997Selan 	  do_spec_1 (" ", 0, NULL_PTR);
320758997Selan 	}
320858997Selan     }
320958997Selan   switches[switchnum].valid = 1;
321058997Selan }
321158997Selan 
321258997Selan /* Search for a file named NAME trying various prefixes including the
321358997Selan    user's -B prefix and some standard ones.
321458997Selan    Return the absolute file name found.  If nothing is found, return NAME.  */
321558997Selan 
321658997Selan static char *
find_file(name)321758997Selan find_file (name)
321858997Selan      char *name;
321958997Selan {
322058997Selan   char *newname;
322158997Selan 
322258997Selan   newname = find_a_file (&startfile_prefix, name, R_OK);
322358997Selan   return newname ? newname : name;
322458997Selan }
322558997Selan 
322658997Selan /* Determine whether a -L option is relevant.  Not required for certain
322758997Selan    fixed names and for directories that don't exist.  */
322858997Selan 
322958997Selan static int
is_linker_dir(path1,path2)323058997Selan is_linker_dir (path1, path2)
323158997Selan      char *path1;
323258997Selan      char *path2;
323358997Selan {
323458997Selan   int len1 = strlen (path1);
323558997Selan   int len2 = strlen (path2);
323658997Selan   char *path = (char *) alloca (3 + len1 + len2);
323758997Selan   char *cp;
323858997Selan   struct stat st;
323958997Selan 
324058997Selan   /* Construct the path from the two parts.  Ensure the string ends with "/.".
324158997Selan      The resulting path will be a directory even if the given path is a
324258997Selan      symbolic link.  */
324358997Selan   bcopy (path1, path, len1);
324458997Selan   bcopy (path2, path + len1, len2);
324558997Selan   cp = path + len1 + len2;
324658997Selan   if (cp[-1] != '/')
324758997Selan     *cp++ = '/';
324858997Selan   *cp++ = '.';
324958997Selan   *cp = '\0';
325058997Selan 
325158997Selan   /* Exclude directories that the linker is known to search.  */
325258997Selan   if ((cp - path == 6 && strcmp (path, "/lib/.") == 0)
325358997Selan       || (cp - path == 10 && strcmp (path, "/usr/lib/.") == 0))
325458997Selan     return 0;
325558997Selan 
325658997Selan   return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
325758997Selan }
325858997Selan 
325958997Selan /* On fatal signals, delete all the temporary files.  */
326058997Selan 
326158997Selan static void
fatal_error(signum)326258997Selan fatal_error (signum)
326358997Selan      int signum;
326458997Selan {
326558997Selan   signal (signum, SIG_DFL);
326658997Selan   delete_failure_queue ();
326758997Selan   delete_temp_files ();
326858997Selan   /* Get the same signal again, this time not handled,
326958997Selan      so its normal effect occurs.  */
327058997Selan   kill (getpid (), signum);
327158997Selan }
327258997Selan 
327358997Selan int
main(argc,argv)327458997Selan main (argc, argv)
327558997Selan      int argc;
327658997Selan      char **argv;
327758997Selan {
327858997Selan   register int i;
327958997Selan   int j;
328058997Selan   int value;
328158997Selan   int error_count = 0;
328258997Selan   int linker_was_run = 0;
328358997Selan   char *explicit_link_files;
328458997Selan   char *specs_file;
328558997Selan 
328658997Selan   programname = argv[0];
328758997Selan 
328858997Selan   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
328958997Selan     signal (SIGINT, fatal_error);
329058997Selan   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
329158997Selan     signal (SIGHUP, fatal_error);
329258997Selan   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
329358997Selan     signal (SIGTERM, fatal_error);
329458997Selan #ifdef SIGPIPE
329558997Selan   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
329658997Selan     signal (SIGPIPE, fatal_error);
329758997Selan #endif
329858997Selan 
329958997Selan   argbuf_length = 10;
330058997Selan   argbuf = (char **) xmalloc (argbuf_length * sizeof (char *));
330158997Selan 
330258997Selan   obstack_init (&obstack);
330358997Selan 
330458997Selan   /* Set up to remember the pathname of gcc and any options
330558997Selan      needed for collect.  */
330658997Selan   obstack_init (&collect_obstack);
330758997Selan   obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=")-1);
330858997Selan   obstack_grow (&collect_obstack, programname, strlen (programname)+1);
330958997Selan   putenv (obstack_finish (&collect_obstack));
331058997Selan 
331158997Selan   /* Choose directory for temp files.  */
331258997Selan 
331358997Selan   choose_temp_base ();
331458997Selan 
331558997Selan   /* Make a table of what switches there are (switches, n_switches).
331658997Selan      Make a table of specified input files (infiles, n_infiles).
331758997Selan      Decode switches that are handled locally.  */
331858997Selan 
331958997Selan   process_command (argc, argv);
332058997Selan 
332158997Selan   /* Initialize the vector of specs to just the default.
332258997Selan      This means one element containing 0s, as a terminator.  */
332358997Selan 
332458997Selan   compilers = (struct compiler *) xmalloc (sizeof default_compilers);
332558997Selan   bcopy (default_compilers, compilers, sizeof default_compilers);
332658997Selan   n_compilers = n_default_compilers;
332758997Selan 
332858997Selan   /* Read specs from a file if there is one.  */
332958997Selan 
333058997Selan   machine_suffix = concat (spec_machine, "/", concat (spec_version, "/", ""));
333158997Selan   just_machine_suffix = concat (spec_machine, "/", "");
333258997Selan 
333358997Selan   specs_file = find_a_file (&startfile_prefix, "specs", R_OK);
333458997Selan   /* Read the specs file unless it is a default one.  */
333558997Selan   if (specs_file != 0 && strcmp (specs_file, "specs"))
333658997Selan     read_specs (specs_file);
333758997Selan 
333858997Selan   /* If not cross-compiling, look for startfiles in the standard places.  */
333958997Selan   /* The fact that these are done here, after reading the specs file,
334058997Selan      means that it cannot be found in these directories.
334158997Selan      But that's okay.  It should never be there anyway.  */
334258997Selan   if (!cross_compile)
334358997Selan     {
334458997Selan #ifdef MD_EXEC_PREFIX
334558997Selan       add_prefix (&exec_prefix, md_exec_prefix, 0, 0, NULL_PTR);
334658997Selan       add_prefix (&startfile_prefix, md_exec_prefix, 0, 0, NULL_PTR);
334758997Selan #endif
334858997Selan 
334958997Selan #ifdef MD_STARTFILE_PREFIX
335058997Selan       add_prefix (&startfile_prefix, md_startfile_prefix, 0, 0, NULL_PTR);
335158997Selan #endif
335258997Selan 
335358997Selan #ifdef MD_STARTFILE_PREFIX_1
335458997Selan       add_prefix (&startfile_prefix, md_startfile_prefix_1, 0, 0, NULL_PTR);
335558997Selan #endif
335658997Selan 
335758997Selan       add_prefix (&startfile_prefix, standard_startfile_prefix, 0, 0,
335858997Selan 		  NULL_PTR);
335958997Selan       add_prefix (&startfile_prefix, standard_startfile_prefix_1, 0, 0,
336058997Selan 		  NULL_PTR);
336158997Selan       add_prefix (&startfile_prefix, standard_startfile_prefix_2, 0, 0,
336258997Selan 		  NULL_PTR);
336358997Selan #if 0 /* Can cause surprises, and one can use -B./ instead.  */
336458997Selan       add_prefix (&startfile_prefix, "./", 0, 1, NULL_PTR);
336558997Selan #endif
336658997Selan     }
336758997Selan 
336858997Selan   /* Now we have the specs.
336958997Selan      Set the `valid' bits for switches that match anything in any spec.  */
337058997Selan 
337158997Selan   validate_all_switches ();
337258997Selan 
337358997Selan   /* Warn about any switches that no pass was interested in.  */
337458997Selan 
337558997Selan   for (i = 0; i < n_switches; i++)
337658997Selan     if (! switches[i].valid)
337758997Selan       error ("unrecognized option `-%s'", switches[i].part1);
337858997Selan 
337958997Selan   if (print_libgcc_file_name)
338058997Selan     {
338158997Selan       printf ("%s\n", find_file ("libgcc.a"));
338258997Selan       exit (0);
338358997Selan     }
338458997Selan 
338558997Selan   /* Obey some of the options.  */
338658997Selan 
338758997Selan   if (verbose_flag)
338858997Selan     {
338958997Selan       fprintf (stderr, "gcc version %s\n", version_string);
339058997Selan       if (n_infiles == 0)
339158997Selan 	exit (0);
339258997Selan     }
339358997Selan 
339458997Selan   if (n_infiles == 0)
339558997Selan     fatal ("No input files specified.");
339658997Selan 
339758997Selan   /* Make a place to record the compiler output file names
339858997Selan      that correspond to the input files.  */
339958997Selan 
340058997Selan   outfiles = (char **) xmalloc (n_infiles * sizeof (char *));
340158997Selan   bzero (outfiles, n_infiles * sizeof (char *));
340258997Selan 
340358997Selan   /* Record which files were specified explicitly as link input.  */
340458997Selan 
340558997Selan   explicit_link_files = xmalloc (n_infiles);
340658997Selan   bzero (explicit_link_files, n_infiles);
340758997Selan 
340858997Selan   for (i = 0; i < n_infiles; i++)
340958997Selan     {
341058997Selan       register struct compiler *cp = 0;
341158997Selan       int this_file_error = 0;
341258997Selan 
341358997Selan       /* Tell do_spec what to substitute for %i.  */
341458997Selan 
341558997Selan       input_filename = infiles[i].name;
341658997Selan       input_filename_length = strlen (input_filename);
341758997Selan       input_file_number = i;
341858997Selan 
341958997Selan       /* Use the same thing in %o, unless cp->spec says otherwise.  */
342058997Selan 
342158997Selan       outfiles[i] = input_filename;
342258997Selan 
342358997Selan       /* Figure out which compiler from the file's suffix.  */
342458997Selan 
342558997Selan       cp = lookup_compiler (infiles[i].name, input_filename_length,
342658997Selan 			    infiles[i].language);
342758997Selan 
342858997Selan       if (cp)
342958997Selan 	{
343058997Selan 	  /* Ok, we found an applicable compiler.  Run its spec.  */
343158997Selan 	  /* First say how much of input_filename to substitute for %b  */
343258997Selan 	  register char *p;
343358997Selan 	  int len;
343458997Selan 
343558997Selan 	  input_basename = input_filename;
343658997Selan 	  for (p = input_filename; *p; p++)
343758997Selan 	    if (*p == '/')
343858997Selan 	      input_basename = p + 1;
343958997Selan 
344058997Selan 	  /* Find a suffix starting with the last period,
344158997Selan 	     and set basename_length to exclude that suffix.  */
344258997Selan 	  basename_length = strlen (input_basename);
344358997Selan 	  p = input_basename + basename_length;
344458997Selan 	  while (p != input_basename && *p != '.') --p;
344558997Selan 	  if (*p == '.' && p != input_basename)
344658997Selan 	    {
344758997Selan 	      basename_length = p - input_basename;
344858997Selan 	      input_suffix = p + 1;
344958997Selan 	    }
345058997Selan 	  else
345158997Selan 	    input_suffix = "";
345258997Selan 
345358997Selan 	  len = 0;
345458997Selan 	  for (j = 0; j < sizeof cp->spec / sizeof cp->spec[0]; j++)
345558997Selan 	    if (cp->spec[j])
345658997Selan 	      len += strlen (cp->spec[j]);
345758997Selan 
345858997Selan 	  p = (char *) xmalloc (len + 1);
345958997Selan 
346058997Selan 	  len = 0;
346158997Selan 	  for (j = 0; j < sizeof cp->spec / sizeof cp->spec[0]; j++)
346258997Selan 	    if (cp->spec[j])
346358997Selan 	      {
346458997Selan 		strcpy (p + len, cp->spec[j]);
346558997Selan 		len += strlen (cp->spec[j]);
346658997Selan 	      }
346758997Selan 
346858997Selan 	  value = do_spec (p);
346958997Selan 	  free (p);
347058997Selan 	  if (value < 0)
347158997Selan 	    this_file_error = 1;
347258997Selan 	}
347358997Selan 
347458997Selan       /* If this file's name does not contain a recognized suffix,
347558997Selan 	 record it as explicit linker input.  */
347658997Selan 
347758997Selan       else
347858997Selan 	explicit_link_files[i] = 1;
347958997Selan 
348058997Selan       /* Clear the delete-on-failure queue, deleting the files in it
348158997Selan 	 if this compilation failed.  */
348258997Selan 
348358997Selan       if (this_file_error)
348458997Selan 	{
348558997Selan 	  delete_failure_queue ();
348658997Selan 	  error_count++;
348758997Selan 	}
348858997Selan       /* If this compilation succeeded, don't delete those files later.  */
348958997Selan       clear_failure_queue ();
349058997Selan     }
349158997Selan 
349258997Selan   /* Run ld to link all the compiler output files.  */
349358997Selan 
349458997Selan   if (error_count == 0)
349558997Selan     {
349658997Selan       int tmp = execution_count;
349758997Selan       int i;
349858997Selan       int first_time;
349958997Selan 
350058997Selan       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
350158997Selan 	 for collect.  */
350258997Selan       putenv_from_prefixes (&exec_prefix, "COMPILER_PATH=");
350358997Selan       putenv_from_prefixes (&startfile_prefix, "LIBRARY_PATH=");
350458997Selan 
350558997Selan       /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
350658997Selan 	 the compiler.  */
350758997Selan       obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
350858997Selan 		    sizeof ("COLLECT_GCC_OPTIONS=")-1);
350958997Selan 
351058997Selan       first_time = TRUE;
351158997Selan       for (i = 0; i < n_switches; i++)
351258997Selan 	{
351358997Selan 	  char **args;
351458997Selan 	  if (!first_time)
351558997Selan 	    obstack_grow (&collect_obstack, " ", 1);
351658997Selan 
351758997Selan 	  first_time = FALSE;
351858997Selan 	  obstack_grow (&collect_obstack, "-", 1);
351958997Selan 	  obstack_grow (&collect_obstack, switches[i].part1,
352058997Selan 			strlen (switches[i].part1));
352158997Selan 
352258997Selan 	  for (args = switches[i].args; args && *args; args++)
352358997Selan 	    {
352458997Selan 	      obstack_grow (&collect_obstack, " ", 1);
352558997Selan 	      obstack_grow (&collect_obstack, *args, strlen (*args));
352658997Selan 	    }
352758997Selan 	}
352858997Selan       obstack_grow (&collect_obstack, "\0", 1);
352958997Selan       putenv (obstack_finish (&collect_obstack));
353058997Selan 
353158997Selan       value = do_spec (link_command_spec);
353258997Selan       if (value < 0)
353358997Selan 	error_count = 1;
353458997Selan       linker_was_run = (tmp != execution_count);
353558997Selan     }
353658997Selan 
353758997Selan   /* Warn if a -B option was specified but the prefix was never used.  */
353858997Selan   unused_prefix_warnings (&exec_prefix);
353958997Selan   unused_prefix_warnings (&startfile_prefix);
354058997Selan 
354158997Selan   /* If options said don't run linker,
354258997Selan      complain about input files to be given to the linker.  */
354358997Selan 
354458997Selan   if (! linker_was_run && error_count == 0)
354558997Selan     for (i = 0; i < n_infiles; i++)
354658997Selan       if (explicit_link_files[i])
354758997Selan 	error ("%s: linker input file unused since linking not done",
354858997Selan 	       outfiles[i]);
354958997Selan 
355058997Selan   /* Delete some or all of the temporary files we made.  */
355158997Selan 
355258997Selan   if (error_count)
355358997Selan     delete_failure_queue ();
355458997Selan   delete_temp_files ();
355558997Selan 
355658997Selan   exit (error_count > 0 ? (signal_count ? 2 : 1) : 0);
355758997Selan   /* NOTREACHED */
355858997Selan   return 0;
355958997Selan }
356058997Selan 
356158997Selan /* Find the proper compilation spec for the file name NAME,
356258997Selan    whose length is LENGTH.  LANGUAGE is the specified language,
356358997Selan    or 0 if none specified.  */
356458997Selan 
356558997Selan static struct compiler *
lookup_compiler(name,length,language)356658997Selan lookup_compiler (name, length, language)
356758997Selan      char *name;
356858997Selan      int length;
356958997Selan      char *language;
357058997Selan {
357158997Selan   struct compiler *cp;
357258997Selan 
357358997Selan   /* Look for the language, if one is spec'd.  */
357458997Selan   if (language != 0)
357558997Selan     {
357658997Selan       for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
357758997Selan 	{
357858997Selan 	  if (language != 0)
357958997Selan 	    {
358058997Selan 	      if (cp->suffix[0] == '@'
358158997Selan 		  && !strcmp (cp->suffix + 1, language))
358258997Selan 		return cp;
358358997Selan 	    }
358458997Selan 	}
358558997Selan       error ("language %s not recognized", language);
358658997Selan     }
358758997Selan 
358858997Selan   /* Look for a suffix.  */
358958997Selan   for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
359058997Selan     {
359158997Selan       if (strlen (cp->suffix) < length
359258997Selan 	       /* See if the suffix matches the end of NAME.  */
359358997Selan 	       && !strcmp (cp->suffix,
359458997Selan 			   name + length - strlen (cp->suffix))
359558997Selan 	       /* The suffix `-' matches only the file name `-'.  */
359658997Selan 	       && !(!strcmp (cp->suffix, "-") && length != 1))
359758997Selan 	{
359858997Selan 	  if (cp->spec[0][0] == '@')
359958997Selan 	    {
360058997Selan 	      struct compiler *new;
360158997Selan 	      /* An alias entry maps a suffix to a language.
360258997Selan 		 Search for the language; pass 0 for NAME and LENGTH
360358997Selan 		 to avoid infinite recursion if language not found.
360458997Selan 		 Construct the new compiler spec.  */
360558997Selan 	      language = cp->spec[0] + 1;
360658997Selan 	      new = (struct compiler *) xmalloc (sizeof (struct compiler));
360758997Selan 	      new->suffix = cp->suffix;
360858997Selan 	      bcopy (lookup_compiler (NULL_PTR, 0, language)->spec,
360958997Selan 		     new->spec, sizeof new->spec);
361058997Selan 	      return new;
361158997Selan 	    }
361258997Selan 	  /* A non-alias entry: return it.  */
361358997Selan 	  return cp;
361458997Selan 	}
361558997Selan     }
361658997Selan 
361758997Selan   return 0;
361858997Selan }
361958997Selan 
362058997Selan char *
xmalloc(size)362158997Selan xmalloc (size)
362258997Selan      unsigned size;
362358997Selan {
362458997Selan   register char *value = (char *) malloc (size);
362558997Selan   if (value == 0)
362658997Selan     fatal ("virtual memory exhausted");
362758997Selan   return value;
362858997Selan }
362958997Selan 
363058997Selan char *
xrealloc(ptr,size)363158997Selan xrealloc (ptr, size)
363258997Selan      char *ptr;
363358997Selan      unsigned size;
363458997Selan {
363558997Selan   register char *value = (char *) realloc (ptr, size);
363658997Selan   if (value == 0)
363758997Selan     fatal ("virtual memory exhausted");
363858997Selan   return value;
363958997Selan }
364058997Selan 
364158997Selan /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
364258997Selan 
364358997Selan static char *
concat(s1,s2,s3)364458997Selan concat (s1, s2, s3)
364558997Selan      char *s1, *s2, *s3;
364658997Selan {
364758997Selan   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
364858997Selan   char *result = xmalloc (len1 + len2 + len3 + 1);
364958997Selan 
365058997Selan   strcpy (result, s1);
365158997Selan   strcpy (result + len1, s2);
365258997Selan   strcpy (result + len1 + len2, s3);
365358997Selan   *(result + len1 + len2 + len3) = 0;
365458997Selan 
365558997Selan   return result;
365658997Selan }
365758997Selan 
365858997Selan static char *
save_string(s,len)365958997Selan save_string (s, len)
366058997Selan      char *s;
366158997Selan      int len;
366258997Selan {
366358997Selan   register char *result = xmalloc (len + 1);
366458997Selan 
366558997Selan   bcopy (s, result, len);
366658997Selan   result[len] = 0;
366758997Selan   return result;
366858997Selan }
366958997Selan 
367058997Selan static void
pfatal_with_name(name)367158997Selan pfatal_with_name (name)
367258997Selan      char *name;
367358997Selan {
367458997Selan   char *s;
367558997Selan 
367658997Selan   if (errno < sys_nerr)
367758997Selan     s = concat ("%s: ", sys_errlist[errno], "");
367858997Selan   else
367958997Selan     s = "cannot open %s";
368058997Selan   fatal (s, name);
368158997Selan }
368258997Selan 
368358997Selan static void
perror_with_name(name)368458997Selan perror_with_name (name)
368558997Selan      char *name;
368658997Selan {
368758997Selan   char *s;
368858997Selan 
368958997Selan   if (errno < sys_nerr)
369058997Selan     s = concat ("%s: ", sys_errlist[errno], "");
369158997Selan   else
369258997Selan     s = "cannot open %s";
369358997Selan   error (s, name);
369458997Selan }
369558997Selan 
369658997Selan static void
perror_exec(name)369758997Selan perror_exec (name)
369858997Selan      char *name;
369958997Selan {
370058997Selan   char *s;
370158997Selan 
370258997Selan   if (errno < sys_nerr)
370358997Selan     s = concat ("installation problem, cannot exec %s: ",
370458997Selan 		sys_errlist[errno], "");
370558997Selan   else
370658997Selan     s = "installation problem, cannot exec %s";
370758997Selan   error (s, name);
370858997Selan }
370958997Selan 
371058997Selan /* More 'friendly' abort that prints the line and file.
371158997Selan    config.h can #define abort fancy_abort if you like that sort of thing.  */
371258997Selan 
371358997Selan void
fancy_abort()371458997Selan fancy_abort ()
371558997Selan {
371658997Selan   fatal ("Internal gcc abort.");
371758997Selan }
371858997Selan 
371958997Selan #ifdef HAVE_VPRINTF
372058997Selan 
372158997Selan /* Output an error message and exit */
372258997Selan 
372358997Selan static void
fatal(va_alist)372458997Selan fatal (va_alist)
372558997Selan      va_dcl
372658997Selan {
372758997Selan   va_list ap;
372858997Selan   char *format;
372958997Selan 
373058997Selan   va_start (ap);
373158997Selan   format = va_arg (ap, char *);
373258997Selan   fprintf (stderr, "%s: ", programname);
373358997Selan   vfprintf (stderr, format, ap);
373458997Selan   va_end (ap);
373558997Selan   fprintf (stderr, "\n");
373658997Selan   delete_temp_files ();
373758997Selan   exit (1);
373858997Selan }
373958997Selan 
374058997Selan static void
error(va_alist)374158997Selan error (va_alist)
374258997Selan      va_dcl
374358997Selan {
374458997Selan   va_list ap;
374558997Selan   char *format;
374658997Selan 
374758997Selan   va_start (ap);
374858997Selan   format = va_arg (ap, char *);
374958997Selan   fprintf (stderr, "%s: ", programname);
375058997Selan   vfprintf (stderr, format, ap);
375158997Selan   va_end (ap);
375258997Selan 
375358997Selan   fprintf (stderr, "\n");
375458997Selan }
375558997Selan 
375658997Selan #else /* not HAVE_VPRINTF */
375758997Selan 
375858997Selan static void
fatal(msg,arg1,arg2)375958997Selan fatal (msg, arg1, arg2)
376058997Selan      char *msg, *arg1, *arg2;
376158997Selan {
376258997Selan   error (msg, arg1, arg2);
376358997Selan   delete_temp_files ();
376458997Selan   exit (1);
376558997Selan }
376658997Selan 
376758997Selan static void
error(msg,arg1,arg2)376858997Selan error (msg, arg1, arg2)
376958997Selan      char *msg, *arg1, *arg2;
377058997Selan {
377158997Selan   fprintf (stderr, "%s: ", programname);
377258997Selan   fprintf (stderr, msg, arg1, arg2);
377358997Selan   fprintf (stderr, "\n");
377458997Selan }
377558997Selan 
377658997Selan #endif /* not HAVE_VPRINTF */
377758997Selan 
377858997Selan 
377958997Selan static void
validate_all_switches()378058997Selan validate_all_switches ()
378158997Selan {
378258997Selan   struct compiler *comp;
378358997Selan   register char *p;
378458997Selan   register char c;
378558997Selan   struct spec_list *spec;
378658997Selan 
378758997Selan   for (comp = compilers; comp->spec[0]; comp++)
378858997Selan     {
378958997Selan       int i;
379058997Selan       for (i = 0; i < sizeof comp->spec / sizeof comp->spec[0] && comp->spec[i]; i++)
379158997Selan 	{
379258997Selan 	  p = comp->spec[i];
379358997Selan 	  while (c = *p++)
379458997Selan 	    if (c == '%' && *p == '{')
379558997Selan 	      /* We have a switch spec.  */
379658997Selan 	      validate_switches (p + 1);
379758997Selan 	}
379858997Selan     }
379958997Selan 
380058997Selan   /* look through the linked list of extra specs read from the specs file */
380158997Selan   for (spec = specs; spec ; spec = spec->next)
380258997Selan     {
380358997Selan       p = spec->spec;
380458997Selan       while (c = *p++)
380558997Selan 	if (c == '%' && *p == '{')
380658997Selan 	  /* We have a switch spec.  */
380758997Selan 	  validate_switches (p + 1);
380858997Selan     }
380958997Selan 
381058997Selan   p = link_command_spec;
381158997Selan   while (c = *p++)
381258997Selan     if (c == '%' && *p == '{')
381358997Selan       /* We have a switch spec.  */
381458997Selan       validate_switches (p + 1);
381558997Selan 
381658997Selan   /* Now notice switches mentioned in the machine-specific specs.  */
381758997Selan 
381858997Selan   p = asm_spec;
381958997Selan   while (c = *p++)
382058997Selan     if (c == '%' && *p == '{')
382158997Selan       /* We have a switch spec.  */
382258997Selan       validate_switches (p + 1);
382358997Selan 
382458997Selan   p = asm_final_spec;
382558997Selan   while (c = *p++)
382658997Selan     if (c == '%' && *p == '{')
382758997Selan       /* We have a switch spec.  */
382858997Selan       validate_switches (p + 1);
382958997Selan 
383058997Selan   p = cpp_spec;
383158997Selan   while (c = *p++)
383258997Selan     if (c == '%' && *p == '{')
383358997Selan       /* We have a switch spec.  */
383458997Selan       validate_switches (p + 1);
383558997Selan 
383658997Selan   p = signed_char_spec;
383758997Selan   while (c = *p++)
383858997Selan     if (c == '%' && *p == '{')
383958997Selan       /* We have a switch spec.  */
384058997Selan       validate_switches (p + 1);
384158997Selan 
384258997Selan   p = cc1_spec;
384358997Selan   while (c = *p++)
384458997Selan     if (c == '%' && *p == '{')
384558997Selan       /* We have a switch spec.  */
384658997Selan       validate_switches (p + 1);
384758997Selan 
384858997Selan   p = cc1plus_spec;
384958997Selan   while (c = *p++)
385058997Selan     if (c == '%' && *p == '{')
385158997Selan       /* We have a switch spec.  */
385258997Selan       validate_switches (p + 1);
385358997Selan 
385458997Selan   p = link_spec;
385558997Selan   while (c = *p++)
385658997Selan     if (c == '%' && *p == '{')
385758997Selan       /* We have a switch spec.  */
385858997Selan       validate_switches (p + 1);
385958997Selan 
386058997Selan   p = lib_spec;
386158997Selan   while (c = *p++)
386258997Selan     if (c == '%' && *p == '{')
386358997Selan       /* We have a switch spec.  */
386458997Selan       validate_switches (p + 1);
386558997Selan 
386658997Selan   p = startfile_spec;
386758997Selan   while (c = *p++)
386858997Selan     if (c == '%' && *p == '{')
386958997Selan       /* We have a switch spec.  */
387058997Selan       validate_switches (p + 1);
387158997Selan }
387258997Selan 
387358997Selan /* Look at the switch-name that comes after START
387458997Selan    and mark as valid all supplied switches that match it.  */
387558997Selan 
387658997Selan static void
validate_switches(start)387758997Selan validate_switches (start)
387858997Selan      char *start;
387958997Selan {
388058997Selan   register char *p = start;
388158997Selan   char *filter;
388258997Selan   register int i;
388358997Selan   int suffix = 0;
388458997Selan 
388558997Selan   if (*p == '|')
388658997Selan     ++p;
388758997Selan 
388858997Selan   if (*p == '!')
388958997Selan     ++p;
389058997Selan 
389158997Selan   if (*p == '.')
389258997Selan     suffix = 1, ++p;
389358997Selan 
389458997Selan   filter = p;
389558997Selan   while (*p != ':' && *p != '}') p++;
389658997Selan 
389758997Selan   if (suffix)
389858997Selan     ;
389958997Selan   else if (p[-1] == '*')
390058997Selan     {
390158997Selan       /* Mark all matching switches as valid.  */
390258997Selan       --p;
390358997Selan       for (i = 0; i < n_switches; i++)
390458997Selan 	if (!strncmp (switches[i].part1, filter, p - filter))
390558997Selan 	  switches[i].valid = 1;
390658997Selan     }
390758997Selan   else
390858997Selan     {
390958997Selan       /* Mark an exact matching switch as valid.  */
391058997Selan       for (i = 0; i < n_switches; i++)
391158997Selan 	{
391258997Selan 	  if (!strncmp (switches[i].part1, filter, p - filter)
391358997Selan 	      && switches[i].part1[p - filter] == 0)
391458997Selan 	    switches[i].valid = 1;
391558997Selan 	}
391658997Selan     }
391758997Selan }
3918