gcc.c revision 90277
118334Speter/* Compiler driver program that can handle many languages.
290277Sobrien   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
390277Sobrien   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
418334Speter
590277SobrienThis file is part of GCC.
618334Speter
790277SobrienGCC is free software; you can redistribute it and/or modify it under
890277Sobrienthe terms of the GNU General Public License as published by the Free
990277SobrienSoftware Foundation; either version 2, or (at your option) any later
1090277Sobrienversion.
1118334Speter
1290277SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390277SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490277SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590277Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890277Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990277SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090277Sobrien02111-1307, USA.
2118334Speter
2218334SpeterThis paragraph is here to try to keep Sun CC from dying.
2318334SpeterThe number of chars here seems crucial!!!!  */
2418334Speter
2551232Sbde/* $FreeBSD: head/contrib/gcc/gcc.c 90277 2002-02-06 02:53:38Z obrien $ */
2651232Sbde
2718334Speter/* This program is the user interface to the C compiler and possibly to
2818334Speterother compilers.  It is used because compilation is a complicated procedure
2918334Speterwhich involves running several programs and passing temporary files between
3018334Speterthem, forwarding the users switches to those programs selectively,
3118334Speterand deleting the temporary files at the end.
3218334Speter
3318334SpeterCC recognizes how to compile each input file by suffixes in the file names.
3418334SpeterOnce it knows which kind of compilation to perform, the procedure for
3518334Spetercompilation is specified by a string called a "spec".  */
3690277Sobrien
3790277Sobrien/* A Short Introduction to Adding a Command-Line Option.
3890277Sobrien
3990277Sobrien   Before adding a command-line option, consider if it is really
4090277Sobrien   necessary.  Each additional command-line option adds complexity and
4190277Sobrien   is difficult to remove in subsequent versions.
4290277Sobrien
4390277Sobrien   In the following, consider adding the command-line argument
4490277Sobrien   `--bar'.
4590277Sobrien
4690277Sobrien   1. Each command-line option is specified in the specs file.  The
4790277Sobrien   notation is described below in the comment entitled "The Specs
4890277Sobrien   Language".  Read it.
4990277Sobrien
5090277Sobrien   2. In this file, add an entry to "option_map" equating the long
5190277Sobrien   `--' argument version and any shorter, single letter version.  Read
5290277Sobrien   the comments in the declaration of "struct option_map" for an
5390277Sobrien   explanation.  Do not omit the first `-'.
5490277Sobrien
5590277Sobrien   3. Look in the "specs" file to determine which program or option
5690277Sobrien   list should be given the argument, e.g., "cc1_options".  Add the
5790277Sobrien   appropriate syntax for the shorter option version to the
5890277Sobrien   corresponding "const char *" entry in this file.  Omit the first
5990277Sobrien   `-' from the option.  For example, use `-bar', rather than `--bar'.
6090277Sobrien
6190277Sobrien   4. If the argument takes an argument, e.g., `--baz argument1',
6290277Sobrien   modify either DEFAULT_SWITCH_TAKES_ARG or
6390277Sobrien   DEFAULT_WORD_SWITCH_TAKES_ARG in this file.  Omit the first `-'
6490277Sobrien   from `--baz'.
6590277Sobrien
6690277Sobrien   5. Document the option in this file's display_help().  If the
6790277Sobrien   option is passed to a subprogram, modify its corresponding
6890277Sobrien   function, e.g., cppinit.c:print_help() or toplev.c:display_help(),
6990277Sobrien   instead.
7090277Sobrien
7190277Sobrien   6. Compile and test.  Make sure that your new specs file is being
7290277Sobrien   read.  For example, use a debugger to investigate the value of
7390277Sobrien   "specs_file" in main().  */
7490277Sobrien
7550599Sobrien#include "config.h"
7650599Sobrien#include "system.h"
7750599Sobrien#include <signal.h>
7890277Sobrien#if ! defined( SIGCHLD ) && defined( SIGCLD )
7990277Sobrien#  define SIGCHLD SIGCLD
8090277Sobrien#endif
8150599Sobrien#include "obstack.h"
8252520Sobrien#include "intl.h"
8352520Sobrien#include "prefix.h"
8490277Sobrien#include "gcc.h"
8590277Sobrien#include "flags.h"
8618334Speter
8790277Sobrien#ifdef HAVE_SYS_RESOURCE_H
8890277Sobrien#include <sys/resource.h>
8918334Speter#endif
9090277Sobrien#if defined (HAVE_DECL_GETRUSAGE) && !HAVE_DECL_GETRUSAGE
9190277Sobrienextern int getrusage PARAMS ((int, struct rusage *));
9290277Sobrien#endif
9318334Speter
9490277Sobrien/* By default there is no special suffix for target executables.  */
9590277Sobrien/* FIXME: when autoconf is fixed, remove the host check - dj */
9690277Sobrien#if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX)
9790277Sobrien#define HAVE_TARGET_EXECUTABLE_SUFFIX
9850599Sobrien#else
9990277Sobrien#undef TARGET_EXECUTABLE_SUFFIX
10090277Sobrien#define TARGET_EXECUTABLE_SUFFIX ""
10118334Speter#endif
10218334Speter
10390277Sobrien/* By default there is no special suffix for host executables.  */
10490277Sobrien#ifdef HOST_EXECUTABLE_SUFFIX
10590277Sobrien#define HAVE_HOST_EXECUTABLE_SUFFIX
10618334Speter#else
10790277Sobrien#define HOST_EXECUTABLE_SUFFIX ""
10818334Speter#endif
10918334Speter
11090277Sobrien/* By default, the suffix for target object files is ".o".  */
11190277Sobrien#ifdef TARGET_OBJECT_SUFFIX
11290277Sobrien#define HAVE_TARGET_OBJECT_SUFFIX
11390277Sobrien#else
11490277Sobrien#define TARGET_OBJECT_SUFFIX ".o"
11518334Speter#endif
11618334Speter
11790277Sobrien#ifndef VMS
11890277Sobrien/* FIXME: the location independence code for VMS is hairier than this,
11990277Sobrien   and hasn't been written.  */
12090277Sobrien#ifndef DIR_UP
12190277Sobrien#define DIR_UP ".."
12290277Sobrien#endif /* DIR_UP */
12390277Sobrien#endif /* VMS */
12418334Speter
12590277Sobrienstatic const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
12652520Sobrien
12718334Speter#define obstack_chunk_alloc xmalloc
12818334Speter#define obstack_chunk_free free
12918334Speter
13052520Sobrien#ifndef GET_ENV_PATH_LIST
13152520Sobrien#define GET_ENV_PATH_LIST(VAR,NAME)	do { (VAR) = getenv (NAME); } while (0)
13218334Speter#endif
13318334Speter
13490277Sobrien/* Most every one is fine with LIBRARY_PATH.  For some, it conflicts.  */
13590277Sobrien#ifndef LIBRARY_PATH_ENV
13690277Sobrien#define LIBRARY_PATH_ENV "LIBRARY_PATH"
13790277Sobrien#endif
13890277Sobrien
13950599Sobrien#ifndef HAVE_KILL
14050599Sobrien#define kill(p,s) raise(s)
14118334Speter#endif
14218334Speter
14318334Speter/* If a stage of compilation returns an exit status >= 1,
14418334Speter   compilation of that file ceases.  */
14518334Speter
14618334Speter#define MIN_FATAL_STATUS 1
14718334Speter
14890277Sobrien/* Flag set by cppspec.c to 1.  */
14990277Sobrienint is_cpp_driver;
15090277Sobrien
15190277Sobrien/* Flag saying to pass the greatest exit code returned by a sub-process
15290277Sobrien   to the calling program.  */
15390277Sobrienstatic int pass_exit_codes;
15490277Sobrien
15590277Sobrien/* Definition of string containing the arguments given to configure.  */
15690277Sobrien#include "configargs.h"
15790277Sobrien
15818334Speter/* Flag saying to print the directories gcc will search through looking for
15918334Speter   programs, libraries, etc.  */
16018334Speter
16118334Speterstatic int print_search_dirs;
16218334Speter
16318334Speter/* Flag saying to print the full filename of this file
16418334Speter   as found through our usual search mechanism.  */
16518334Speter
16652520Sobrienstatic const char *print_file_name = NULL;
16718334Speter
16850599Sobrien/* As print_file_name, but search for executable file.  */
16918334Speter
17052520Sobrienstatic const char *print_prog_name = NULL;
17118334Speter
17218334Speter/* Flag saying to print the relative path we'd use to
17318334Speter   find libgcc.a given the current compiler flags.  */
17418334Speter
17518334Speterstatic int print_multi_directory;
17618334Speter
17718334Speter/* Flag saying to print the list of subdirectories and
17818334Speter   compiler flags used to select them in a standard form.  */
17918334Speter
18018334Speterstatic int print_multi_lib;
18118334Speter
18250599Sobrien/* Flag saying to print the command line options understood by gcc and its
18350599Sobrien   sub-processes.  */
18450599Sobrien
18550599Sobrienstatic int print_help_list;
18650599Sobrien
18718334Speter/* Flag indicating whether we should print the command and arguments */
18818334Speter
18918334Speterstatic int verbose_flag;
19018334Speter
19190277Sobrien/* Flag indicating whether we should ONLY print the command and
19290277Sobrien   arguments (like verbose_flag) without executing the command.
19390277Sobrien   Displayed arguments are quoted so that the generated command
19490277Sobrien   line is suitable for execution.  This is intended for use in
19590277Sobrien   shell scripts to capture the driver-generated command line.  */
19690277Sobrienstatic int verbose_only_flag;
19790277Sobrien
19890277Sobrien/* Flag indicating to print target specific command line options.  */
19990277Sobrien
20090277Sobrienstatic int target_help_flag;
20190277Sobrien
20290277Sobrien/* Flag indicating whether we should report subprocess execution times
20390277Sobrien   (if this is supported by the system - see pexecute.c).  */
20490277Sobrien
20590277Sobrienstatic int report_times;
20690277Sobrien
20718334Speter/* Nonzero means write "temp" files in source directory
20818334Speter   and use the source file's name in them, and don't delete them.  */
20918334Speter
21018334Speterstatic int save_temps_flag;
21118334Speter
21218334Speter/* The compiler version.  */
21318334Speter
21490277Sobrienstatic const char *compiler_version;
21518334Speter
21618334Speter/* The target version specified with -V */
21718334Speter
21890277Sobrienstatic const char *spec_version = DEFAULT_TARGET_VERSION;
21918334Speter
22018334Speter/* The target machine specified with -b.  */
22118334Speter
22252520Sobrienstatic const char *spec_machine = DEFAULT_TARGET_MACHINE;
22318334Speter
22418334Speter/* Nonzero if cross-compiling.
22518334Speter   When -b is used, the value comes from the `specs' file.  */
22618334Speter
22718334Speter#ifdef CROSS_COMPILE
22890277Sobrienstatic const char *cross_compile = "1";
22918334Speter#else
23090277Sobrienstatic const char *cross_compile = "0";
23118334Speter#endif
23218334Speter
23390277Sobrien#ifdef MODIFY_TARGET_NAME
23490277Sobrien
23590277Sobrien/* Information on how to alter the target name based on a command-line
23690277Sobrien   switch.  The only case we support now is simply appending or deleting a
23790277Sobrien   string to or from the end of the first part of the configuration name.  */
23890277Sobrien
23990277Sobrienstatic const struct modify_target
24090277Sobrien{
24190277Sobrien  const char *const sw;
24290277Sobrien  const enum add_del {ADD, DELETE} add_del;
24390277Sobrien  const char *const str;
24490277Sobrien}
24590277Sobrienmodify_target[] = MODIFY_TARGET_NAME;
24690277Sobrien#endif
24790277Sobrien
24818334Speter/* The number of errors that have occurred; the link phase will not be
24918334Speter   run if this is non-zero.  */
25018334Speterstatic int error_count = 0;
25118334Speter
25290277Sobrien/* Greatest exit code of sub-processes that has been encountered up to
25390277Sobrien   now.  */
25490277Sobrienstatic int greatest_status = 1;
25590277Sobrien
25618334Speter/* This is the obstack which we use to allocate many strings.  */
25718334Speter
25818334Speterstatic struct obstack obstack;
25918334Speter
26018334Speter/* This is the obstack to build an environment variable to pass to
26118334Speter   collect2 that describes all of the relevant switches of what to
26218334Speter   pass the compiler in building the list of pointers to constructors
26318334Speter   and destructors.  */
26418334Speter
26518334Speterstatic struct obstack collect_obstack;
26618334Speter
26790277Sobrien/* These structs are used to collect resource usage information for
26890277Sobrien   subprocesses.  */
26990277Sobrien#ifdef HAVE_GETRUSAGE
27090277Sobrienstatic struct rusage rus, prus;
27190277Sobrien#endif
27218334Speter
27318334Speter/* Forward declaration for prototypes.  */
27418334Speterstruct path_prefix;
27518334Speter
27690277Sobrienstatic void init_spec		PARAMS ((void));
27790277Sobrien#ifndef VMS
27890277Sobrienstatic char **split_directories	PARAMS ((const char *, int *));
27990277Sobrienstatic void free_split_directories PARAMS ((char **));
28090277Sobrienstatic char *make_relative_prefix PARAMS ((const char *, const char *, const char *));
28190277Sobrien#endif /* VMS */
28290277Sobrienstatic void store_arg		PARAMS ((const char *, int, int));
28390277Sobrienstatic char *load_specs		PARAMS ((const char *));
28490277Sobrienstatic void read_specs		PARAMS ((const char *, int));
28590277Sobrienstatic void set_spec		PARAMS ((const char *, const char *));
28690277Sobrienstatic struct compiler *lookup_compiler PARAMS ((const char *, size_t, const char *));
28790277Sobrienstatic char *build_search_list	PARAMS ((struct path_prefix *, const char *, int));
28890277Sobrienstatic void putenv_from_prefixes PARAMS ((struct path_prefix *, const char *));
28990277Sobrienstatic int access_check		PARAMS ((const char *, int));
29090277Sobrienstatic char *find_a_file	PARAMS ((struct path_prefix *, const char *, int));
29190277Sobrienstatic void add_prefix		PARAMS ((struct path_prefix *, const char *,
29290277Sobrien					 const char *, int, int, int *));
29390277Sobrienstatic void translate_options	PARAMS ((int *, const char *const **));
29490277Sobrienstatic char *skip_whitespace	PARAMS ((char *));
29590277Sobrienstatic void delete_if_ordinary	PARAMS ((const char *));
29690277Sobrienstatic void delete_temp_files	PARAMS ((void));
29790277Sobrienstatic void delete_failure_queue PARAMS ((void));
29890277Sobrienstatic void clear_failure_queue PARAMS ((void));
29990277Sobrienstatic int check_live_switch	PARAMS ((int, int));
30090277Sobrienstatic const char *handle_braces PARAMS ((const char *));
30190277Sobrienstatic char *save_string	PARAMS ((const char *, int));
30290277Sobrienstatic void set_collect_gcc_options PARAMS ((void));
30390277Sobrienstatic int do_spec_1		PARAMS ((const char *, int, const char *));
30490277Sobrienstatic const char *find_file	PARAMS ((const char *));
30590277Sobrienstatic int is_directory		PARAMS ((const char *, const char *, int));
30690277Sobrienstatic void validate_switches	PARAMS ((const char *));
30790277Sobrienstatic void validate_all_switches PARAMS ((void));
30890277Sobrienstatic void give_switch		PARAMS ((int, int, int));
30990277Sobrienstatic int used_arg		PARAMS ((const char *, int));
31090277Sobrienstatic int default_arg		PARAMS ((const char *, int));
31190277Sobrienstatic void set_multilib_dir	PARAMS ((void));
31290277Sobrienstatic void print_multilib_info	PARAMS ((void));
31390277Sobrienstatic void perror_with_name	PARAMS ((const char *));
31490277Sobrienstatic void pfatal_pexecute	PARAMS ((const char *, const char *))
31552520Sobrien  ATTRIBUTE_NORETURN;
31690277Sobrienstatic void notice		PARAMS ((const char *, ...))
31752520Sobrien  ATTRIBUTE_PRINTF_1;
31890277Sobrienstatic void display_help 	PARAMS ((void));
31990277Sobrienstatic void add_preprocessor_option	PARAMS ((const char *, int));
32090277Sobrienstatic void add_assembler_option	PARAMS ((const char *, int));
32190277Sobrienstatic void add_linker_option		PARAMS ((const char *, int));
32290277Sobrienstatic void process_command		PARAMS ((int, const char *const *));
32390277Sobrienstatic int execute			PARAMS ((void));
32490277Sobrienstatic void clear_args			PARAMS ((void));
32590277Sobrienstatic void fatal_error			PARAMS ((int));
32690277Sobrien#ifdef ENABLE_SHARED_LIBGCC
32790277Sobrienstatic void init_gcc_specs              PARAMS ((struct obstack *,
32890277Sobrien						 const char *, const char *,
32990277Sobrien						 const char *));
33090277Sobrien#endif
33190277Sobrien#if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
33290277Sobrienstatic const char *convert_filename	PARAMS ((const char *, int, int));
33390277Sobrien#endif
33490277Sobrien
33590277Sobrien/* The Specs Language
33618334Speter
33790277SobrienSpecs are strings containing lines, each of which (if not blank)
33818334Speteris made up of a program name, and arguments separated by spaces.
33918334SpeterThe program name must be exact and start from root, since no path
34018334Speteris searched and it is unreliable to depend on the current working directory.
34118334SpeterRedirection of input or output is not supported; the subprograms must
34218334Speteraccept filenames saying what files to read and write.
34318334Speter
34418334SpeterIn addition, the specs can contain %-sequences to substitute variable text
34518334Speteror for conditional text.  Here is a table of all defined %-sequences.
34618334SpeterNote that spaces are not generated automatically around the results of
34718334Speterexpanding these sequences; therefore, you can concatenate them together
34818334Speteror with constant text in a single argument.
34918334Speter
35018334Speter %%	substitute one % into the program name or argument.
35118334Speter %i     substitute the name of the input file being processed.
35218334Speter %b     substitute the basename of the input file being processed.
35318334Speter	This is the substring up to (and not including) the last period
35418334Speter	and not including the directory.
35590277Sobrien %B	same as %b, but include the file suffix (text after the last period).
35650599Sobrien %gSUFFIX
35750599Sobrien	substitute a file name that has suffix SUFFIX and is chosen
35850599Sobrien	once per compilation, and mark the argument a la %d.  To reduce
35950599Sobrien	exposure to denial-of-service attacks, the file name is now
36050599Sobrien	chosen in a way that is hard to predict even when previously
36150599Sobrien	chosen file names are known.  For example, `%g.s ... %g.o ... %g.s'
36250599Sobrien	might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'.  SUFFIX matches
36390277Sobrien	the regexp "[.A-Za-z]*%O"; "%O" is treated exactly as if it
36490277Sobrien	had been pre-processed.  Previously, %g was simply substituted
36590277Sobrien	with a file name chosen once per compilation, without regard
36690277Sobrien	to any appended suffix (which was therefore treated just like
36790277Sobrien	ordinary text), making such attacks more likely to succeed.
36850599Sobrien %uSUFFIX
36950599Sobrien	like %g, but generates a new temporary file name even if %uSUFFIX
37050599Sobrien	was already seen.
37150599Sobrien %USUFFIX
37250599Sobrien	substitutes the last file name generated with %uSUFFIX, generating a
37350599Sobrien	new one if there is no such last file name.  In the absence of any
37450599Sobrien	%uSUFFIX, this is just like %gSUFFIX, except they don't share
37550599Sobrien	the same suffix "space", so `%g.s ... %U.s ... %g.s ... %U.s'
37650599Sobrien	would involve the generation of two distinct file names, one
37750599Sobrien	for each `%g.s' and another for each `%U.s'.  Previously, %U was
37850599Sobrien	simply substituted with a file name chosen for the previous %u,
37950599Sobrien	without regard to any appended suffix.
38090277Sobrien %jSUFFIX
38190277Sobrien        substitutes the name of the HOST_BIT_BUCKET, if any, and if it is
38290277Sobrien        writable, and if save-temps is off; otherwise, substitute the name
38390277Sobrien        of a temporary file, just like %u.  This temporary file is not
38490277Sobrien        meant for communication between processes, but rather as a junk
38590277Sobrien        disposal mechanism.
38690277Sobrien %.SUFFIX
38790277Sobrien        substitutes .SUFFIX for the suffixes of a matched switch's args when
38890277Sobrien        it is subsequently output with %*. SUFFIX is terminated by the next
38990277Sobrien        space or %.
39018334Speter %d	marks the argument containing or following the %d as a
39118334Speter	temporary file name, so that that file will be deleted if CC exits
39218334Speter	successfully.  Unlike %g, this contributes no text to the argument.
39318334Speter %w	marks the argument containing or following the %w as the
39418334Speter	"output file" of this compilation.  This puts the argument
39518334Speter	into the sequence of arguments that %o will substitute later.
39618334Speter %W{...}
39718334Speter	like %{...} but mark last argument supplied within
39818334Speter	as a file to be deleted on failure.
39918334Speter %o	substitutes the names of all the output files, with spaces
40018334Speter	automatically placed around them.  You should write spaces
40118334Speter	around the %o as well or the results are undefined.
40218334Speter	%o is for use in the specs for running the linker.
40318334Speter	Input files whose names have no recognized suffix are not compiled
40418334Speter	at all, but they are included among the output files, so they will
40518334Speter	be linked.
40650599Sobrien %O	substitutes the suffix for object files.  Note that this is
40790277Sobrien        handled specially when it immediately follows %g, %u, or %U
40890277Sobrien	(with or without a suffix argument) because of the need for
40990277Sobrien	those to form complete file names.  The handling is such that
41090277Sobrien	%O is treated exactly as if it had already been substituted,
41190277Sobrien	except that %g, %u, and %U do not currently support additional
41290277Sobrien	SUFFIX characters following %O as they would following, for
41390277Sobrien	example, `.o'.
41418334Speter %p	substitutes the standard macro predefinitions for the
41518334Speter	current target machine.  Use this when running cpp.
41618334Speter %P	like %p, but puts `__' before and after the name of each macro.
41718334Speter	(Except macros that already have __.)
41818334Speter	This is for ANSI C.
41918334Speter %I	Substitute a -iprefix option made from GCC_EXEC_PREFIX.
42018334Speter %s     current argument is the name of a library or startup file of some sort.
42118334Speter        Search for that file in a standard list of directories
42218334Speter	and substitute the full name found.
42318334Speter %eSTR  Print STR as an error message.  STR is terminated by a newline.
42418334Speter        Use this when inconsistent options are detected.
42590277Sobrien %nSTR  Print STR as an notice.  STR is terminated by a newline.
42618334Speter %x{OPTION}	Accumulate an option for %X.
42718334Speter %X	Output the accumulated linker options specified by compilations.
42818334Speter %Y	Output the accumulated assembler options specified by compilations.
42918334Speter %Z	Output the accumulated preprocessor options specified by compilations.
43018334Speter %v1	Substitute the major version number of GCC.
43190277Sobrien	(For version 2.5.3, this is 2.)
43218334Speter %v2	Substitute the minor version number of GCC.
43390277Sobrien	(For version 2.5.3, this is 5.)
43490277Sobrien %v3	Substitute the patch level number of GCC.
43590277Sobrien	(For version 2.5.3, this is 3.)
43618334Speter %a     process ASM_SPEC as a spec.
43718334Speter        This allows config.h to specify part of the spec for running as.
43818334Speter %A	process ASM_FINAL_SPEC as a spec.  A capital A is actually
43918334Speter	used here.  This can be used to run a post-processor after the
44050599Sobrien	assembler has done its job.
44118334Speter %D	Dump out a -L option for each directory in startfile_prefixes.
44218334Speter	If multilib_dir is set, extra entries are generated with it affixed.
44318334Speter %l     process LINK_SPEC as a spec.
44418334Speter %L     process LIB_SPEC as a spec.
44518334Speter %G     process LIBGCC_SPEC as a spec.
44690277Sobrien %M     output multilib_dir with directory separators replaced with "_";
44790277Sobrien	if multilib_dir is not set or is ".", output "".
44818334Speter %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
44918334Speter %E     process ENDFILE_SPEC as a spec.  A capital E is actually used here.
45018334Speter %c	process SIGNED_CHAR_SPEC as a spec.
45190277Sobrien %C     process CPP_SPEC as a spec.
45218334Speter %1	process CC1_SPEC as a spec.
45318334Speter %2	process CC1PLUS_SPEC as a spec.
45418334Speter %|	output "-" if the input for the current command is coming from a pipe.
45518334Speter %*	substitute the variable part of a matched option.  (See below.)
45618334Speter	Note that each comma in the substituted string is replaced by
45718334Speter	a single space.
45818334Speter %{S}   substitutes the -S switch, if that switch was given to CC.
45918334Speter	If that switch was not specified, this substitutes nothing.
46018334Speter	Here S is a metasyntactic variable.
46118334Speter %{S*}  substitutes all the switches specified to CC whose names start
46290277Sobrien	with -S.  This is used for -o, -I, etc; switches that take
46318334Speter	arguments.  CC considers `-o foo' as being one switch whose
46418334Speter	name starts with `o'.  %{o*} would substitute this text,
46518334Speter	including the space; thus, two arguments would be generated.
46650599Sobrien %{^S*} likewise, but don't put a blank between a switch and any args.
46790277Sobrien %{S*&T*} likewise, but preserve order of S and T options (the order
46890277Sobrien 	of S and T in the spec is not significant).  Can be any number
46990277Sobrien 	of ampersand-separated variables; for each the wild card is
47090277Sobrien 	optional.  Useful for CPP as %{D*&U*&A*}.
47118334Speter %{S*:X} substitutes X if one or more switches whose names start with -S are
47218334Speter	specified to CC.  Note that the tail part of the -S option
47318334Speter	(i.e. the part matched by the `*') will be substituted for each
47418334Speter	occurrence of %* within X.
47590277Sobrien %{<S}  remove all occurrences of -S from the command line.
47690277Sobrien        Note - this option is position dependent.  % commands in the
47790277Sobrien        spec string before this option will see -S, % commands in the
47890277Sobrien        spec string after this option will not.
47918334Speter %{S:X} substitutes X, but only if the -S switch was given to CC.
48018334Speter %{!S:X} substitutes X, but only if the -S switch was NOT given to CC.
48118334Speter %{|S:X} like %{S:X}, but if no S switch, substitute `-'.
48218334Speter %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
48318334Speter %{.S:X} substitutes X, but only if processing a file with suffix S.
48418334Speter %{!.S:X} substitutes X, but only if NOT processing a file with suffix S.
48550599Sobrien %{S|P:X} substitutes X if either -S or -P was given to CC.  This may be
48650599Sobrien	  combined with ! and . as above binding stronger than the OR.
48718334Speter %(Spec) processes a specification defined in a specs file as *Spec:
48818334Speter %[Spec] as above, but put __ around -D arguments
48918334Speter
49018334SpeterThe conditional text X in a %{S:X} or %{!S:X} construct may contain
49118334Speterother nested % constructs or spaces, or even newlines.  They are
49218334Speterprocessed as usual, as described above.
49318334Speter
49418334SpeterThe -O, -f, -m, and -W switches are handled specifically in these
49518334Speterconstructs.  If another value of -O or the negated form of a -f, -m, or
49618334Speter-W switch is found later in the command line, the earlier switch
49718334Spetervalue is ignored, except with {S*} where S is just one letter; this
49818334Speterpasses all matching options.
49918334Speter
50050599SobrienThe character | at the beginning of the predicate text is used to indicate
50150599Sobrienthat a command should be piped to the following command, but only if -pipe
50250599Sobrienis specified.
50318334Speter
50418334SpeterNote that it is built into CC which switches take arguments and which
50518334Speterdo not.  You might think it would be useful to generalize this to
50618334Speterallow each compiler's spec to say which switches take arguments.  But
50718334Speterthis cannot be done in a consistent fashion.  CC cannot even decide
50818334Speterwhich input files have been specified without knowing which switches
50918334Spetertake arguments, and it must know which input files to compile in order
51018334Speterto tell which compilers to run.
51118334Speter
51218334SpeterCC also knows implicitly that arguments starting in `-l' are to be
51318334Spetertreated as compiler output files, and passed to the linker in their
51418334Speterproper position among the other output files.  */
51518334Speter
51618334Speter/* Define the macros used for specs %a, %l, %L, %S, %c, %C, %1.  */
51718334Speter
51818334Speter/* config.h can define ASM_SPEC to provide extra args to the assembler
51918334Speter   or extra switch-translations.  */
52018334Speter#ifndef ASM_SPEC
52118334Speter#define ASM_SPEC ""
52218334Speter#endif
52318334Speter
52418334Speter/* config.h can define ASM_FINAL_SPEC to run a post processor after
52518334Speter   the assembler has run.  */
52618334Speter#ifndef ASM_FINAL_SPEC
52718334Speter#define ASM_FINAL_SPEC ""
52818334Speter#endif
52918334Speter
53018334Speter/* config.h can define CPP_SPEC to provide extra args to the C preprocessor
53118334Speter   or extra switch-translations.  */
53218334Speter#ifndef CPP_SPEC
53318334Speter#define CPP_SPEC ""
53418334Speter#endif
53518334Speter
53618334Speter/* config.h can define CC1_SPEC to provide extra args to cc1 and cc1plus
53718334Speter   or extra switch-translations.  */
53818334Speter#ifndef CC1_SPEC
53918334Speter#define CC1_SPEC ""
54018334Speter#endif
54118334Speter
54218334Speter/* config.h can define CC1PLUS_SPEC to provide extra args to cc1plus
54318334Speter   or extra switch-translations.  */
54418334Speter#ifndef CC1PLUS_SPEC
54518334Speter#define CC1PLUS_SPEC ""
54618334Speter#endif
54718334Speter
54818334Speter/* config.h can define LINK_SPEC to provide extra args to the linker
54918334Speter   or extra switch-translations.  */
55018334Speter#ifndef LINK_SPEC
55118334Speter#define LINK_SPEC ""
55218334Speter#endif
55318334Speter
55418334Speter/* config.h can define LIB_SPEC to override the default libraries.  */
55518334Speter#ifndef LIB_SPEC
55618334Speter#define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
55718334Speter#endif
55818334Speter
55918334Speter/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
56018334Speter   included.  */
56118334Speter#ifndef LIBGCC_SPEC
56218334Speter#if defined(LINK_LIBGCC_SPECIAL) || defined(LINK_LIBGCC_SPECIAL_1)
56318334Speter/* Have gcc do the search for libgcc.a.  */
56450599Sobrien#define LIBGCC_SPEC "libgcc.a%s"
56518334Speter#else
56650599Sobrien#define LIBGCC_SPEC "-lgcc"
56718334Speter#endif
56818334Speter#endif
56918334Speter
57018334Speter/* config.h can define STARTFILE_SPEC to override the default crt0 files.  */
57118334Speter#ifndef STARTFILE_SPEC
57218334Speter#define STARTFILE_SPEC  \
57318334Speter  "%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
57418334Speter#endif
57518334Speter
57650599Sobrien/* config.h can define SWITCHES_NEED_SPACES to control which options
57750599Sobrien   require spaces between the option and the argument.  */
57818334Speter#ifndef SWITCHES_NEED_SPACES
57918334Speter#define SWITCHES_NEED_SPACES ""
58018334Speter#endif
58118334Speter
58218334Speter/* config.h can define ENDFILE_SPEC to override the default crtn files.  */
58318334Speter#ifndef ENDFILE_SPEC
58418334Speter#define ENDFILE_SPEC ""
58518334Speter#endif
58618334Speter
58718334Speter/* This spec is used for telling cpp whether char is signed or not.  */
58818334Speter#ifndef SIGNED_CHAR_SPEC
58918334Speter/* Use #if rather than ?:
59018334Speter   because MIPS C compiler rejects like ?: in initializers.  */
59118334Speter#if DEFAULT_SIGNED_CHAR
59218334Speter#define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
59318334Speter#else
59418334Speter#define SIGNED_CHAR_SPEC "%{!fsigned-char:-D__CHAR_UNSIGNED__}"
59518334Speter#endif
59618334Speter#endif
59718334Speter
59850599Sobrien#ifndef LINKER_NAME
59950599Sobrien#define LINKER_NAME "collect2"
60018334Speter#endif
60118334Speter
60290277Sobrien/* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
60390277Sobrien   to the assembler.  */
60490277Sobrien#ifndef ASM_DEBUG_SPEC
60590277Sobrien# if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
60690277Sobrien     && defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
60790277Sobrien#  define ASM_DEBUG_SPEC					\
60890277Sobrien      (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG			\
60990277Sobrien       ? "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}"	\
61090277Sobrien       : "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}")
61190277Sobrien# else
61290277Sobrien#  if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
61390277Sobrien#   define ASM_DEBUG_SPEC "%{g*:--gstabs}"
61490277Sobrien#  endif
61590277Sobrien#  if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
61690277Sobrien#   define ASM_DEBUG_SPEC "%{g*:--gdwarf2}"
61790277Sobrien#  endif
61890277Sobrien# endif
61990277Sobrien#endif
62090277Sobrien#ifndef ASM_DEBUG_SPEC
62190277Sobrien# define ASM_DEBUG_SPEC ""
62290277Sobrien#endif
62318334Speter
62490277Sobrien/* Here is the spec for running the linker, after compiling all files.  */
62590277Sobrien
62690277Sobrien/* -u* was put back because both BSD and SysV seem to support it.  */
62790277Sobrien/* %{static:} simply prevents an error message if the target machine
62890277Sobrien   doesn't handle -static.  */
62990277Sobrien/* We want %{T*} after %{L*} and %D so that it can be used to specify linker
63090277Sobrien   scripts which exist in user specified directories, or in standard
63190277Sobrien   directories.  */
63290277Sobrien#ifndef LINK_COMMAND_SPEC
63390277Sobrien#define LINK_COMMAND_SPEC "\
63490277Sobrien%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
63590277Sobrien    %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t}\
63690277Sobrien    %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
63790277Sobrien    %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
63890277Sobrien    %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
63990277Sobrien#endif
64090277Sobrien
64190277Sobrien#ifndef LINK_LIBGCC_SPEC
64290277Sobrien# ifdef LINK_LIBGCC_SPECIAL
64390277Sobrien/* Don't generate -L options for startfile prefix list.  */
64490277Sobrien#  define LINK_LIBGCC_SPEC ""
64590277Sobrien# else
64690277Sobrien/* Do generate them.  */
64790277Sobrien#  define LINK_LIBGCC_SPEC "%D"
64890277Sobrien# endif
64990277Sobrien#endif
65090277Sobrien
65190277Sobrienstatic const char *asm_debug = ASM_DEBUG_SPEC;
65290277Sobrienstatic const char *cpp_spec = CPP_SPEC;
65390277Sobrienstatic const char *cpp_predefines = CPP_PREDEFINES;
65490277Sobrienstatic const char *cc1_spec = CC1_SPEC;
65590277Sobrienstatic const char *cc1plus_spec = CC1PLUS_SPEC;
65690277Sobrienstatic const char *signed_char_spec = SIGNED_CHAR_SPEC;
65790277Sobrienstatic const char *asm_spec = ASM_SPEC;
65890277Sobrienstatic const char *asm_final_spec = ASM_FINAL_SPEC;
65990277Sobrienstatic const char *link_spec = LINK_SPEC;
66090277Sobrienstatic const char *lib_spec = LIB_SPEC;
66190277Sobrienstatic const char *libgcc_spec = LIBGCC_SPEC;
66290277Sobrienstatic const char *endfile_spec = ENDFILE_SPEC;
66390277Sobrienstatic const char *startfile_spec = STARTFILE_SPEC;
66490277Sobrienstatic const char *switches_need_spaces = SWITCHES_NEED_SPACES;
66590277Sobrienstatic const char *linker_name_spec = LINKER_NAME;
66690277Sobrienstatic const char *link_command_spec = LINK_COMMAND_SPEC;
66790277Sobrienstatic const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
66890277Sobrien
66990277Sobrien/* Standard options to cpp, cc1, and as, to reduce duplication in specs.
67090277Sobrien   There should be no need to override these in target dependent files,
67190277Sobrien   but we need to copy them to the specs file so that newer versions
67290277Sobrien   of the GCC driver can correctly drive older tool chains with the
67390277Sobrien   appropriate -B options.  */
67490277Sobrien
67590277Sobrienstatic const char *trad_capable_cpp =
67690277Sobrien"%{traditional|ftraditional|traditional-cpp:trad}cpp0";
67790277Sobrien
67890277Sobrienstatic const char *cpp_unique_options =
67990277Sobrien"%{C:%{!E:%eGNU C does not support -C without using -E}}\
68090277Sobrien %{nostdinc*} %{C} %{v} %{I*} %{P} %{$} %I\
68190277Sobrien %{MD:-M -MF %W{!o: %b.d}%W{o*:%.d%*}}\
68290277Sobrien %{MMD:-MM -MF %W{!o: %b.d}%W{o*:%.d%*}}\
68390277Sobrien %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{M|MD|MM|MMD:%{o*:-MQ %*}}\
68490277Sobrien %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3}\
68590277Sobrien %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
68690277Sobrien %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
68790277Sobrien %{fno-inline|O0|!O*:-D__NO_INLINE__} %{ffast-math:-D__FAST_MATH__}\
68890277Sobrien %{fshort-wchar:-U__WCHAR_TYPE__ -D__WCHAR_TYPE__=short\\ unsigned\\ int}\
68990277Sobrien %{ffreestanding:-D__STDC_HOSTED__=0} %{fno-hosted:-D__STDC_HOSTED__=0}\
69090277Sobrien %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}} %{remap}\
69190277Sobrien %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
69290277Sobrien %{E:%{!M*:%W{o*}}}";
69390277Sobrien
69490277Sobrien/* This contains cpp options which are common with cc1_options and are passed
69590277Sobrien   only when preprocessing only to avoid duplication.  */
69690277Sobrienstatic const char *cpp_options =
69790277Sobrien"%(cpp_unique_options) %{std*} %{d*} %{W*} %{w} %{pedantic*}\
69890277Sobrien %{fshow-column} %{fno-show-column}\
69990277Sobrien %{fleading-underscore} %{fno-leading-underscore}\
70090277Sobrien %{fno-operator-names} %{ftabstop=*}";
70190277Sobrien
70290277Sobrien/* NB: This is shared amongst all front-ends.  */
70390277Sobrienstatic const char *cc1_options =
70490277Sobrien"%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
70590277Sobrien %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
70690277Sobrien %{g*} %{O*} %{W*} %{w} %{pedantic*} %{std*} %{ansi}\
70790277Sobrien %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
70890277Sobrien %{Qn:-fno-ident} %{--help:--help}\
70990277Sobrien %{--target-help:--target-help}\
71090277Sobrien %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
71190277Sobrien %{fsyntax-only:-o %j} %{-param*}";
71290277Sobrien
71390277Sobrienstatic const char *asm_options =
71490277Sobrien"%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
71590277Sobrien
71690277Sobrienstatic const char *invoke_as =
71790277Sobrien"%{!S:-o %{|!pipe:%g.s} |\n as %(asm_options) %{!pipe:%g.s} %A }";
71890277Sobrien
71950599Sobrien/* Some compilers have limits on line lengths, and the multilib_select
72050599Sobrien   and/or multilib_matches strings can be very long, so we build them at
72150599Sobrien   run time.  */
72250599Sobrienstatic struct obstack multilib_obstack;
72390277Sobrienstatic const char *multilib_select;
72490277Sobrienstatic const char *multilib_matches;
72590277Sobrienstatic const char *multilib_defaults;
72690277Sobrienstatic const char *multilib_exclusions;
72750599Sobrien#include "multilib.h"
72850599Sobrien
72950599Sobrien/* Check whether a particular argument is a default argument.  */
73050599Sobrien
73150599Sobrien#ifndef MULTILIB_DEFAULTS
73250599Sobrien#define MULTILIB_DEFAULTS { "" }
73350599Sobrien#endif
73450599Sobrien
73590277Sobrienstatic const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
73650599Sobrien
73790277Sobrienstruct user_specs
73890277Sobrien{
73950599Sobrien  struct user_specs *next;
74052520Sobrien  const char *filename;
74150599Sobrien};
74250599Sobrien
74350599Sobrienstatic struct user_specs *user_specs_head, *user_specs_tail;
74450599Sobrien
74518334Speter/* This defines which switch letters take arguments.  */
74618334Speter
74750599Sobrien#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
74818334Speter  ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
74918334Speter   || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
75018334Speter   || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
75150599Sobrien   || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \
75250599Sobrien   || (CHAR) == 'B' || (CHAR) == 'b')
75350599Sobrien
75450599Sobrien#ifndef SWITCH_TAKES_ARG
75550599Sobrien#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
75618334Speter#endif
75718334Speter
75818334Speter/* This defines which multi-letter switches take arguments.  */
75918334Speter
76018334Speter#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)		\
76118334Speter (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")	\
76218334Speter  || !strcmp (STR, "Tbss") || !strcmp (STR, "include")	\
76318334Speter  || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
76418334Speter  || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
76518334Speter  || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
76690277Sobrien  || !strcmp (STR, "isystem") || !strcmp (STR, "-param") \
76790277Sobrien  || !strcmp (STR, "specs") \
76890277Sobrien  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ"))
76918334Speter
77018334Speter#ifndef WORD_SWITCH_TAKES_ARG
77118334Speter#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
77218334Speter#endif
77318334Speter
77490277Sobrien#ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
77550599Sobrien/* This defines which switches stop a full compilation.  */
77650599Sobrien#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
77750599Sobrien  ((CHAR) == 'c' || (CHAR) == 'S')
77850599Sobrien
77950599Sobrien#ifndef SWITCH_CURTAILS_COMPILATION
78050599Sobrien#define SWITCH_CURTAILS_COMPILATION(CHAR) \
78150599Sobrien  DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR)
78250599Sobrien#endif
78350599Sobrien#endif
78450599Sobrien
78518334Speter/* Record the mapping from file suffixes for compilation specs.  */
78618334Speter
78718334Speterstruct compiler
78818334Speter{
78952520Sobrien  const char *suffix;		/* Use this compiler for input files
79018334Speter				   whose names end in this suffix.  */
79118334Speter
79290277Sobrien  const char *spec;		/* To use this compiler, run this spec.  */
79390277Sobrien
79490277Sobrien  const char *cpp_spec;         /* If non-NULL, substitute this spec
79590277Sobrien				   for `%C', rather than the usual
79690277Sobrien				   cpp_spec.  */
79718334Speter};
79818334Speter
79918334Speter/* Pointer to a vector of `struct compiler' that gives the spec for
80018334Speter   compiling a file, based on its suffix.
80118334Speter   A file that does not end in any of these suffixes will be passed
80218334Speter   unchanged to the loader and nothing else will be done to it.
80318334Speter
80418334Speter   An entry containing two 0s is used to terminate the vector.
80518334Speter
80618334Speter   If multiple entries match a file, the last matching one is used.  */
80718334Speter
80818334Speterstatic struct compiler *compilers;
80918334Speter
81018334Speter/* Number of entries in `compilers', not counting the null terminator.  */
81118334Speter
81218334Speterstatic int n_compilers;
81318334Speter
81418334Speter/* The default list of file name suffixes and their compilation specs.  */
81518334Speter
81690277Sobrienstatic const struct compiler default_compilers[] =
81718334Speter{
81850599Sobrien  /* Add lists of suffixes of known languages here.  If those languages
81950599Sobrien     were not present when we built the driver, we will hit these copies
82050599Sobrien     and be given a more meaningful error than "file not used since
82150599Sobrien     linking is not done".  */
82290277Sobrien  {".m",  "#Objective-C", 0}, {".mi",  "#Objective-C", 0},
82390277Sobrien  {".cc", "#C++", 0}, {".cxx", "#C++", 0}, {".cpp", "#C++", 0},
82490277Sobrien  {".cp", "#C++", 0}, {".c++", "#C++", 0}, {".C", "#C++", 0},
82590277Sobrien  {".ii", "#C++", 0},
82690277Sobrien  {".ads", "#Ada", 0}, {".adb", "#Ada", 0},
82790277Sobrien  {".f", "#Fortran", 0}, {".for", "#Fortran", 0}, {".fpp", "#Fortran", 0},
82890277Sobrien  {".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0},
82990277Sobrien  {".r", "#Ratfor", 0},
83090277Sobrien  {".p", "#Pascal", 0}, {".pas", "#Pascal", 0},
83190277Sobrien  {".ch", "#Chill", 0}, {".chi", "#Chill", 0},
83290277Sobrien  {".java", "#Java", 0}, {".class", "#Java", 0},
83390277Sobrien  {".zip", "#Java", 0}, {".jar", "#Java", 0},
83450599Sobrien  /* Next come the entries for C.  */
83590277Sobrien  {".c", "@c", 0},
83618334Speter  {"@c",
83790277Sobrien   /* cc1 has an integrated ISO C preprocessor.  We should invoke the
83890277Sobrien      external preprocessor if -save-temps or -traditional is given.  */
83990277Sobrien     "%{E|M|MM:%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)}\
84090277Sobrien      %{!E:%{!M:%{!MM:\
84190277Sobrien	  %{save-temps:%(trad_capable_cpp) -lang-c %{ansi:-std=c89}\
84290277Sobrien		%(cpp_options) %b.i \n\
84390277Sobrien		    cc1 -fpreprocessed %b.i %(cc1_options)}\
84490277Sobrien	  %{!save-temps:\
84590277Sobrien	    %{traditional|ftraditional|traditional-cpp:\
84690277Sobrien		tradcpp0 -lang-c %{ansi:-std=c89} %(cpp_options) %{!pipe:%g.i} |\n\
84790277Sobrien		    cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\
84890277Sobrien	    %{!traditional:%{!ftraditional:%{!traditional-cpp:\
84990277Sobrien		cc1 -lang-c %{ansi:-std=c89} %(cpp_unique_options) %(cc1_options)}}}}\
85090277Sobrien        %{!fsyntax-only:%(invoke_as)}}}}", 0},
85118334Speter  {"-",
85290277Sobrien   "%{!E:%e-E required when input is from standard input}\
85390277Sobrien    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
85490277Sobrien  {".h", "@c-header", 0},
85518334Speter  {"@c-header",
85690277Sobrien   "%{!E:%ecompilation of header file requested} \
85790277Sobrien    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
85890277Sobrien  {".i", "@cpp-output", 0},
85918334Speter  {"@cpp-output",
86090277Sobrien   "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0},
86190277Sobrien  {".s", "@assembler", 0},
86218334Speter  {"@assembler",
86390277Sobrien   "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0},
86490277Sobrien  {".S", "@assembler-with-cpp", 0},
86518334Speter  {"@assembler-with-cpp",
86690277Sobrien   "%(trad_capable_cpp) -lang-asm %(cpp_options)\
86790277Sobrien      %{!M:%{!MM:%{!E:%{!S:-o %{|!pipe:%g.s} |\n\
86890277Sobrien       as %(asm_debug) %(asm_options) %{!pipe:%g.s} %A }}}}", 0},
86918334Speter#include "specs.h"
87018334Speter  /* Mark end of table */
87190277Sobrien  {0, 0, 0}
87218334Speter};
87318334Speter
87418334Speter/* Number of elements in default_compilers, not counting the terminator.  */
87518334Speter
87618334Speterstatic int n_default_compilers
87718334Speter  = (sizeof default_compilers / sizeof (struct compiler)) - 1;
87818334Speter
87918334Speter/* A vector of options to give to the linker.
88018334Speter   These options are accumulated by %x,
88118334Speter   and substituted into the linker command with %X.  */
88218334Speterstatic int n_linker_options;
88318334Speterstatic char **linker_options;
88418334Speter
88518334Speter/* A vector of options to give to the assembler.
88618334Speter   These options are accumulated by -Wa,
88718334Speter   and substituted into the assembler command with %Y.  */
88818334Speterstatic int n_assembler_options;
88918334Speterstatic char **assembler_options;
89018334Speter
89118334Speter/* A vector of options to give to the preprocessor.
89218334Speter   These options are accumulated by -Wp,
89318334Speter   and substituted into the preprocessor command with %Z.  */
89418334Speterstatic int n_preprocessor_options;
89518334Speterstatic char **preprocessor_options;
89618334Speter
89718334Speter/* Define how to map long options into short ones.  */
89818334Speter
89918334Speter/* This structure describes one mapping.  */
90018334Speterstruct option_map
90118334Speter{
90218334Speter  /* The long option's name.  */
90390277Sobrien  const char *const name;
90418334Speter  /* The equivalent short option.  */
90590277Sobrien  const char *const equivalent;
90618334Speter  /* Argument info.  A string of flag chars; NULL equals no options.
90718334Speter     a => argument required.
90818334Speter     o => argument optional.
90918334Speter     j => join argument to equivalent, making one word.
91018334Speter     * => require other text after NAME as an argument.  */
91190277Sobrien  const char *const arg_info;
91218334Speter};
91318334Speter
91418334Speter/* This is the table of mappings.  Mappings are tried sequentially
91518334Speter   for each option encountered; the first one that matches, wins.  */
91618334Speter
91790277Sobrienstatic const struct option_map option_map[] =
91818334Speter {
91918334Speter   {"--all-warnings", "-Wall", 0},
92018334Speter   {"--ansi", "-ansi", 0},
92118334Speter   {"--assemble", "-S", 0},
92218334Speter   {"--assert", "-A", "a"},
92352520Sobrien   {"--classpath", "-fclasspath=", "aj"},
92452520Sobrien   {"--CLASSPATH", "-fCLASSPATH=", "aj"},
92518334Speter   {"--comments", "-C", 0},
92618334Speter   {"--compile", "-c", 0},
92718334Speter   {"--debug", "-g", "oj"},
92850599Sobrien   {"--define-macro", "-D", "aj"},
92918334Speter   {"--dependencies", "-M", 0},
93018334Speter   {"--dump", "-d", "a"},
93118334Speter   {"--dumpbase", "-dumpbase", "a"},
93218334Speter   {"--entry", "-e", 0},
93318334Speter   {"--extra-warnings", "-W", 0},
93418334Speter   {"--for-assembler", "-Wa", "a"},
93518334Speter   {"--for-linker", "-Xlinker", "a"},
93618334Speter   {"--force-link", "-u", "a"},
93718334Speter   {"--imacros", "-imacros", "a"},
93818334Speter   {"--include", "-include", "a"},
93918334Speter   {"--include-barrier", "-I-", 0},
94050599Sobrien   {"--include-directory", "-I", "aj"},
94118334Speter   {"--include-directory-after", "-idirafter", "a"},
94218334Speter   {"--include-prefix", "-iprefix", "a"},
94318334Speter   {"--include-with-prefix", "-iwithprefix", "a"},
94418334Speter   {"--include-with-prefix-before", "-iwithprefixbefore", "a"},
94518334Speter   {"--include-with-prefix-after", "-iwithprefix", "a"},
94618334Speter   {"--language", "-x", "a"},
94718334Speter   {"--library-directory", "-L", "a"},
94818334Speter   {"--machine", "-m", "aj"},
94918334Speter   {"--machine-", "-m", "*j"},
95018334Speter   {"--no-line-commands", "-P", 0},
95118334Speter   {"--no-precompiled-includes", "-noprecomp", 0},
95218334Speter   {"--no-standard-includes", "-nostdinc", 0},
95318334Speter   {"--no-standard-libraries", "-nostdlib", 0},
95418334Speter   {"--no-warnings", "-w", 0},
95518334Speter   {"--optimize", "-O", "oj"},
95618334Speter   {"--output", "-o", "a"},
95752520Sobrien   {"--output-class-directory", "-foutput-class-dir=", "ja"},
95890277Sobrien   {"--param", "--param", "a"},
95918334Speter   {"--pedantic", "-pedantic", 0},
96018334Speter   {"--pedantic-errors", "-pedantic-errors", 0},
96118334Speter   {"--pipe", "-pipe", 0},
96218334Speter   {"--prefix", "-B", "a"},
96318334Speter   {"--preprocess", "-E", 0},
96418334Speter   {"--print-search-dirs", "-print-search-dirs", 0},
96518334Speter   {"--print-file-name", "-print-file-name=", "aj"},
96618334Speter   {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
96718334Speter   {"--print-missing-file-dependencies", "-MG", 0},
96818334Speter   {"--print-multi-lib", "-print-multi-lib", 0},
96918334Speter   {"--print-multi-directory", "-print-multi-directory", 0},
97018334Speter   {"--print-prog-name", "-print-prog-name=", "aj"},
97118334Speter   {"--profile", "-p", 0},
97218334Speter   {"--profile-blocks", "-a", 0},
97318334Speter   {"--quiet", "-q", 0},
97418334Speter   {"--save-temps", "-save-temps", 0},
97518334Speter   {"--shared", "-shared", 0},
97618334Speter   {"--silent", "-q", 0},
97750599Sobrien   {"--specs", "-specs=", "aj"},
97818334Speter   {"--static", "-static", 0},
97952520Sobrien   {"--std", "-std=", "aj"},
98018334Speter   {"--symbolic", "-symbolic", 0},
98118334Speter   {"--target", "-b", "a"},
98290277Sobrien   {"--time", "-time", 0},
98318334Speter   {"--trace-includes", "-H", 0},
98418334Speter   {"--traditional", "-traditional", 0},
98518334Speter   {"--traditional-cpp", "-traditional-cpp", 0},
98618334Speter   {"--trigraphs", "-trigraphs", 0},
98750599Sobrien   {"--undefine-macro", "-U", "aj"},
98818334Speter   {"--use-version", "-V", "a"},
98918334Speter   {"--user-dependencies", "-MM", 0},
99018334Speter   {"--verbose", "-v", 0},
99118334Speter   {"--warn-", "-W", "*j"},
99218334Speter   {"--write-dependencies", "-MD", 0},
99318334Speter   {"--write-user-dependencies", "-MMD", 0},
99418334Speter   {"--", "-f", "*j"}
99518334Speter };
99618334Speter
99790277Sobrien
99890277Sobrien#ifdef TARGET_OPTION_TRANSLATE_TABLE
99990277Sobrienstatic const struct {
100090277Sobrien  const char *const option_found;
100190277Sobrien  const char *const replacements;
100290277Sobrien} target_option_translations[] =
100390277Sobrien{
100490277Sobrien  TARGET_OPTION_TRANSLATE_TABLE,
100590277Sobrien  { 0, 0 }
100690277Sobrien};
100790277Sobrien#endif
100890277Sobrien
100918334Speter/* Translate the options described by *ARGCP and *ARGVP.
101018334Speter   Make a new vector and store it back in *ARGVP,
101118334Speter   and store its length in *ARGVC.  */
101218334Speter
101318334Speterstatic void
101418334Spetertranslate_options (argcp, argvp)
101518334Speter     int *argcp;
101690277Sobrien     const char *const **argvp;
101718334Speter{
101852520Sobrien  int i;
101918334Speter  int argc = *argcp;
102090277Sobrien  const char *const *argv = *argvp;
102190277Sobrien  int newvsize = (argc + 2) * 2 * sizeof (const char *);
102252520Sobrien  const char **newv =
102390277Sobrien    (const char **) xmalloc (newvsize);
102418334Speter  int newindex = 0;
102518334Speter
102618334Speter  i = 0;
102718334Speter  newv[newindex++] = argv[i++];
102818334Speter
102918334Speter  while (i < argc)
103018334Speter    {
103190277Sobrien#ifdef TARGET_OPTION_TRANSLATE_TABLE
103290277Sobrien      int tott_idx;
103390277Sobrien
103490277Sobrien      for (tott_idx = 0;
103590277Sobrien	   target_option_translations[tott_idx].option_found;
103690277Sobrien	   tott_idx++)
103790277Sobrien	{
103890277Sobrien	  if (strcmp (target_option_translations[tott_idx].option_found,
103990277Sobrien		      argv[i]) == 0)
104090277Sobrien	    {
104190277Sobrien	      int spaces = 1;
104290277Sobrien	      const char *sp;
104390277Sobrien	      char *np;
104490277Sobrien
104590277Sobrien	      for (sp = target_option_translations[tott_idx].replacements;
104690277Sobrien		   *sp; sp++)
104790277Sobrien		{
104890277Sobrien		  if (*sp == ' ')
104990277Sobrien		    spaces ++;
105090277Sobrien		}
105190277Sobrien
105290277Sobrien	      newvsize += spaces * sizeof (const char *);
105390277Sobrien	      newv = (const char **) xrealloc (newv, newvsize);
105490277Sobrien
105590277Sobrien	      sp = target_option_translations[tott_idx].replacements;
105690277Sobrien	      np = xstrdup (sp);
105790277Sobrien
105890277Sobrien	      while (1)
105990277Sobrien		{
106090277Sobrien		  while (*np == ' ')
106190277Sobrien		    np++;
106290277Sobrien		  if (*np == 0)
106390277Sobrien		    break;
106490277Sobrien		  newv[newindex++] = np;
106590277Sobrien		  while (*np != ' ' && *np)
106690277Sobrien		    np++;
106790277Sobrien		  if (*np == 0)
106890277Sobrien		    break;
106990277Sobrien		  *np++ = 0;
107090277Sobrien		}
107190277Sobrien
107290277Sobrien	      i ++;
107390277Sobrien	      break;
107490277Sobrien	    }
107590277Sobrien	}
107690277Sobrien      if (target_option_translations[tott_idx].option_found)
107790277Sobrien	continue;
107890277Sobrien#endif
107990277Sobrien
108018334Speter      /* Translate -- options.  */
108118334Speter      if (argv[i][0] == '-' && argv[i][1] == '-')
108218334Speter	{
108352520Sobrien	  size_t j;
108418334Speter	  /* Find a mapping that applies to this option.  */
108590277Sobrien	  for (j = 0; j < ARRAY_SIZE (option_map); j++)
108618334Speter	    {
108750599Sobrien	      size_t optlen = strlen (option_map[j].name);
108850599Sobrien	      size_t arglen = strlen (argv[i]);
108950599Sobrien	      size_t complen = arglen > optlen ? optlen : arglen;
109052520Sobrien	      const char *arginfo = option_map[j].arg_info;
109118334Speter
109218334Speter	      if (arginfo == 0)
109318334Speter		arginfo = "";
109418334Speter
109518334Speter	      if (!strncmp (argv[i], option_map[j].name, complen))
109618334Speter		{
109752520Sobrien		  const char *arg = 0;
109818334Speter
109918334Speter		  if (arglen < optlen)
110018334Speter		    {
110152520Sobrien		      size_t k;
110290277Sobrien		      for (k = j + 1; k < ARRAY_SIZE (option_map); k++)
110318334Speter			if (strlen (option_map[k].name) >= arglen
110418334Speter			    && !strncmp (argv[i], option_map[k].name, arglen))
110518334Speter			  {
110690277Sobrien			    error ("ambiguous abbreviation %s", argv[i]);
110718334Speter			    break;
110818334Speter			  }
110918334Speter
111090277Sobrien		      if (k != ARRAY_SIZE (option_map))
111118334Speter			break;
111218334Speter		    }
111318334Speter
111418334Speter		  if (arglen > optlen)
111518334Speter		    {
111618334Speter		      /* If the option has an argument, accept that.  */
111718334Speter		      if (argv[i][optlen] == '=')
111818334Speter			arg = argv[i] + optlen + 1;
111918334Speter
112018334Speter		      /* If this mapping requires extra text at end of name,
112118334Speter			 accept that as "argument".  */
112290277Sobrien		      else if (strchr (arginfo, '*') != 0)
112318334Speter			arg = argv[i] + optlen;
112418334Speter
112518334Speter		      /* Otherwise, extra text at end means mismatch.
112618334Speter			 Try other mappings.  */
112718334Speter		      else
112818334Speter			continue;
112918334Speter		    }
113018334Speter
113190277Sobrien		  else if (strchr (arginfo, '*') != 0)
113218334Speter		    {
113390277Sobrien		      error ("incomplete `%s' option", option_map[j].name);
113418334Speter		      break;
113518334Speter		    }
113618334Speter
113718334Speter		  /* Handle arguments.  */
113890277Sobrien		  if (strchr (arginfo, 'a') != 0)
113918334Speter		    {
114018334Speter		      if (arg == 0)
114118334Speter			{
114218334Speter			  if (i + 1 == argc)
114318334Speter			    {
114490277Sobrien			      error ("missing argument to `%s' option",
114518334Speter				     option_map[j].name);
114618334Speter			      break;
114718334Speter			    }
114818334Speter
114918334Speter			  arg = argv[++i];
115018334Speter			}
115118334Speter		    }
115290277Sobrien		  else if (strchr (arginfo, '*') != 0)
115318334Speter		    ;
115490277Sobrien		  else if (strchr (arginfo, 'o') == 0)
115518334Speter		    {
115618334Speter		      if (arg != 0)
115790277Sobrien			error ("extraneous argument to `%s' option",
115818334Speter			       option_map[j].name);
115918334Speter		      arg = 0;
116018334Speter		    }
116118334Speter
116218334Speter		  /* Store the translation as one argv elt or as two.  */
116390277Sobrien		  if (arg != 0 && strchr (arginfo, 'j') != 0)
116450599Sobrien		    newv[newindex++] = concat (option_map[j].equivalent, arg,
116590277Sobrien					       NULL);
116618334Speter		  else if (arg != 0)
116718334Speter		    {
116818334Speter		      newv[newindex++] = option_map[j].equivalent;
116918334Speter		      newv[newindex++] = arg;
117018334Speter		    }
117118334Speter		  else
117218334Speter		    newv[newindex++] = option_map[j].equivalent;
117318334Speter
117418334Speter		  break;
117518334Speter		}
117618334Speter	    }
117718334Speter	  i++;
117818334Speter	}
117918334Speter
118018334Speter      /* Handle old-fashioned options--just copy them through,
118118334Speter	 with their arguments.  */
118218334Speter      else if (argv[i][0] == '-')
118318334Speter	{
118452520Sobrien	  const char *p = argv[i] + 1;
118518334Speter	  int c = *p;
118618334Speter	  int nskip = 1;
118718334Speter
118818334Speter	  if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
118918334Speter	    nskip += SWITCH_TAKES_ARG (c) - (p[1] != 0);
119018334Speter	  else if (WORD_SWITCH_TAKES_ARG (p))
119118334Speter	    nskip += WORD_SWITCH_TAKES_ARG (p);
119218334Speter	  else if ((c == 'B' || c == 'b' || c == 'V' || c == 'x')
119318334Speter		   && p[1] == 0)
119418334Speter	    nskip += 1;
119518334Speter	  else if (! strcmp (p, "Xlinker"))
119618334Speter	    nskip += 1;
119718334Speter
119818334Speter	  /* Watch out for an option at the end of the command line that
119918334Speter	     is missing arguments, and avoid skipping past the end of the
120018334Speter	     command line.  */
120118334Speter	  if (nskip + i > argc)
120218334Speter	    nskip = argc - i;
120318334Speter
120418334Speter	  while (nskip > 0)
120518334Speter	    {
120618334Speter	      newv[newindex++] = argv[i++];
120718334Speter	      nskip--;
120818334Speter	    }
120918334Speter	}
121018334Speter      else
121118334Speter	/* Ordinary operands, or +e options.  */
121218334Speter	newv[newindex++] = argv[i++];
121318334Speter    }
121418334Speter
121518334Speter  newv[newindex] = 0;
121618334Speter
121718334Speter  *argvp = newv;
121818334Speter  *argcp = newindex;
121918334Speter}
122018334Speter
122118334Speterstatic char *
122218334Speterskip_whitespace (p)
122318334Speter     char *p;
122418334Speter{
122518334Speter  while (1)
122618334Speter    {
122718334Speter      /* A fully-blank line is a delimiter in the SPEC file and shouldn't
122818334Speter	 be considered whitespace.  */
122918334Speter      if (p[0] == '\n' && p[1] == '\n' && p[2] == '\n')
123018334Speter	return p + 1;
123118334Speter      else if (*p == '\n' || *p == ' ' || *p == '\t')
123218334Speter	p++;
123318334Speter      else if (*p == '#')
123418334Speter	{
123590277Sobrien	  while (*p != '\n')
123690277Sobrien	    p++;
123718334Speter	  p++;
123818334Speter	}
123918334Speter      else
124018334Speter	break;
124118334Speter    }
124218334Speter
124318334Speter  return p;
124418334Speter}
124590277Sobrien/* Structures to keep track of prefixes to try when looking for files.  */
124690277Sobrien
124790277Sobrienstruct prefix_list
124890277Sobrien{
124990277Sobrien  const char *prefix;	      /* String to prepend to the path.  */
125090277Sobrien  struct prefix_list *next;   /* Next in linked list.  */
125190277Sobrien  int require_machine_suffix; /* Don't use without machine_suffix.  */
125290277Sobrien  /* 2 means try both machine_suffix and just_machine_suffix.  */
125390277Sobrien  int *used_flag_ptr;	      /* 1 if a file was found with this prefix.  */
125490277Sobrien  int priority;		      /* Sort key - priority within list */
125590277Sobrien};
125690277Sobrien
125790277Sobrienstruct path_prefix
125890277Sobrien{
125990277Sobrien  struct prefix_list *plist;  /* List of prefixes to try */
126090277Sobrien  int max_len;                /* Max length of a prefix in PLIST */
126190277Sobrien  const char *name;           /* Name of this list (used in config stuff) */
126290277Sobrien};
126390277Sobrien
126490277Sobrien/* List of prefixes to try when looking for executables.  */
126590277Sobrien
126690277Sobrienstatic struct path_prefix exec_prefixes = { 0, 0, "exec" };
126790277Sobrien
126890277Sobrien/* List of prefixes to try when looking for startup (crt0) files.  */
126990277Sobrien
127090277Sobrienstatic struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
127190277Sobrien
127290277Sobrien/* List of prefixes to try when looking for include files.  */
127390277Sobrien
127490277Sobrienstatic struct path_prefix include_prefixes = { 0, 0, "include" };
127590277Sobrien
127690277Sobrien/* Suffix to attach to directories searched for commands.
127790277Sobrien   This looks like `MACHINE/VERSION/'.  */
127890277Sobrien
127990277Sobrienstatic const char *machine_suffix = 0;
128090277Sobrien
128190277Sobrien/* Suffix to attach to directories searched for commands.
128290277Sobrien   This is just `MACHINE/'.  */
128390277Sobrien
128490277Sobrienstatic const char *just_machine_suffix = 0;
128590277Sobrien
128690277Sobrien/* Adjusted value of GCC_EXEC_PREFIX envvar.  */
128790277Sobrien
128890277Sobrienstatic const char *gcc_exec_prefix;
128990277Sobrien
129090277Sobrien/* Default prefixes to attach to command names.  */
129190277Sobrien
129290277Sobrien#ifdef CROSS_COMPILE  /* Don't use these prefixes for a cross compiler.  */
129390277Sobrien#undef MD_EXEC_PREFIX
129490277Sobrien#undef MD_STARTFILE_PREFIX
129590277Sobrien#undef MD_STARTFILE_PREFIX_1
129690277Sobrien#endif
129790277Sobrien
129890277Sobrien/* If no prefixes defined, use the null string, which will disable them.  */
129990277Sobrien#ifndef MD_EXEC_PREFIX
130090277Sobrien#define MD_EXEC_PREFIX ""
130190277Sobrien#endif
130290277Sobrien#ifndef MD_STARTFILE_PREFIX
130390277Sobrien#define MD_STARTFILE_PREFIX ""
130490277Sobrien#endif
130590277Sobrien#ifndef MD_STARTFILE_PREFIX_1
130690277Sobrien#define MD_STARTFILE_PREFIX_1 ""
130790277Sobrien#endif
130890277Sobrien
130990277Sobrien/* Supply defaults for the standard prefixes.  */
131090277Sobrien
131190277Sobrien#ifndef STANDARD_EXEC_PREFIX
131290277Sobrien#define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-lib/"
131390277Sobrien#endif
131490277Sobrien#ifndef STANDARD_STARTFILE_PREFIX
131590277Sobrien#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/"
131690277Sobrien#endif
131790277Sobrien#ifndef TOOLDIR_BASE_PREFIX
131890277Sobrien#define TOOLDIR_BASE_PREFIX "/usr/local/"
131990277Sobrien#endif
132090277Sobrien#ifndef STANDARD_BINDIR_PREFIX
132190277Sobrien#define STANDARD_BINDIR_PREFIX "/usr/local/bin"
132290277Sobrien#endif
132390277Sobrien
132490277Sobrienstatic const char *const standard_exec_prefix = STANDARD_EXEC_PREFIX;
132590277Sobrienstatic const char *const standard_exec_prefix_1 = "/usr/lib/gcc/";
132690277Sobrienstatic const char *md_exec_prefix = MD_EXEC_PREFIX;
132790277Sobrien
132890277Sobrienstatic const char *md_startfile_prefix = MD_STARTFILE_PREFIX;
132990277Sobrienstatic const char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
133090277Sobrienstatic const char *const standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
133190277Sobrienstatic const char *const standard_startfile_prefix_1 = "/lib/";
133290277Sobrienstatic const char *const standard_startfile_prefix_2 = "/usr/lib/";
133390277Sobrien
133490277Sobrienstatic const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
133590277Sobrienstatic const char *tooldir_prefix;
133690277Sobrien
133790277Sobrienstatic const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
133890277Sobrien
133990277Sobrien/* Subdirectory to use for locating libraries.  Set by
134090277Sobrien   set_multilib_dir based on the compilation options.  */
134190277Sobrien
134290277Sobrienstatic const char *multilib_dir;
134318334Speter
134450599Sobrien/* Structure to keep track of the specs that have been defined so far.
134550599Sobrien   These are accessed using %(specname) or %[specname] in a compiler
134650599Sobrien   or link spec.  */
134718334Speter
134818334Speterstruct spec_list
134918334Speter{
135050599Sobrien				/* The following 2 fields must be first */
135150599Sobrien				/* to allow EXTRA_SPECS to be initialized */
135290277Sobrien  const char *name;		/* name of the spec.  */
135390277Sobrien  const char *ptr;		/* available ptr if no static pointer */
135450599Sobrien
135550599Sobrien				/* The following fields are not initialized */
135650599Sobrien				/* by EXTRA_SPECS */
135790277Sobrien  const char **ptr_spec;	/* pointer to the spec itself.  */
135850599Sobrien  struct spec_list *next;	/* Next spec in linked list.  */
135950599Sobrien  int name_len;			/* length of the name */
136050599Sobrien  int alloc_p;			/* whether string was allocated */
136118334Speter};
136218334Speter
136350599Sobrien#define INIT_STATIC_SPEC(NAME,PTR) \
136490277Sobrien{ NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, 0 }
136518334Speter
136690277Sobrien/* List of statically defined specs.  */
136790277Sobrienstatic struct spec_list static_specs[] =
136890277Sobrien{
136950599Sobrien  INIT_STATIC_SPEC ("asm",			&asm_spec),
137090277Sobrien  INIT_STATIC_SPEC ("asm_debug",		&asm_debug),
137150599Sobrien  INIT_STATIC_SPEC ("asm_final",		&asm_final_spec),
137290277Sobrien  INIT_STATIC_SPEC ("asm_options",		&asm_options),
137390277Sobrien  INIT_STATIC_SPEC ("invoke_as",		&invoke_as),
137450599Sobrien  INIT_STATIC_SPEC ("cpp",			&cpp_spec),
137590277Sobrien  INIT_STATIC_SPEC ("cpp_options",		&cpp_options),
137690277Sobrien  INIT_STATIC_SPEC ("cpp_unique_options",	&cpp_unique_options),
137790277Sobrien  INIT_STATIC_SPEC ("trad_capable_cpp",		&trad_capable_cpp),
137850599Sobrien  INIT_STATIC_SPEC ("cc1",			&cc1_spec),
137990277Sobrien  INIT_STATIC_SPEC ("cc1_options",		&cc1_options),
138050599Sobrien  INIT_STATIC_SPEC ("cc1plus",			&cc1plus_spec),
138150599Sobrien  INIT_STATIC_SPEC ("endfile",			&endfile_spec),
138250599Sobrien  INIT_STATIC_SPEC ("link",			&link_spec),
138350599Sobrien  INIT_STATIC_SPEC ("lib",			&lib_spec),
138450599Sobrien  INIT_STATIC_SPEC ("libgcc",			&libgcc_spec),
138550599Sobrien  INIT_STATIC_SPEC ("startfile",		&startfile_spec),
138650599Sobrien  INIT_STATIC_SPEC ("switches_need_spaces",	&switches_need_spaces),
138750599Sobrien  INIT_STATIC_SPEC ("signed_char",		&signed_char_spec),
138850599Sobrien  INIT_STATIC_SPEC ("predefines",		&cpp_predefines),
138950599Sobrien  INIT_STATIC_SPEC ("cross_compile",		&cross_compile),
139050599Sobrien  INIT_STATIC_SPEC ("version",			&compiler_version),
139150599Sobrien  INIT_STATIC_SPEC ("multilib",			&multilib_select),
139250599Sobrien  INIT_STATIC_SPEC ("multilib_defaults",	&multilib_defaults),
139350599Sobrien  INIT_STATIC_SPEC ("multilib_extra",		&multilib_extra),
139450599Sobrien  INIT_STATIC_SPEC ("multilib_matches",		&multilib_matches),
139590277Sobrien  INIT_STATIC_SPEC ("multilib_exclusions",	&multilib_exclusions),
139650599Sobrien  INIT_STATIC_SPEC ("linker",			&linker_name_spec),
139790277Sobrien  INIT_STATIC_SPEC ("link_libgcc",		&link_libgcc_spec),
139890277Sobrien  INIT_STATIC_SPEC ("md_exec_prefix",		&md_exec_prefix),
139990277Sobrien  INIT_STATIC_SPEC ("md_startfile_prefix",	&md_startfile_prefix),
140090277Sobrien  INIT_STATIC_SPEC ("md_startfile_prefix_1",	&md_startfile_prefix_1),
140150599Sobrien};
140250599Sobrien
140350599Sobrien#ifdef EXTRA_SPECS		/* additional specs needed */
140452520Sobrien/* Structure to keep track of just the first two args of a spec_list.
140590277Sobrien   That is all that the EXTRA_SPECS macro gives us.  */
140652520Sobrienstruct spec_list_1
140752520Sobrien{
140890277Sobrien  const char *const name;
140990277Sobrien  const char *const ptr;
141052520Sobrien};
141152520Sobrien
141290277Sobrienstatic const struct spec_list_1 extra_specs_1[] = { EXTRA_SPECS };
141390277Sobrienstatic struct spec_list *extra_specs = (struct spec_list *) 0;
141450599Sobrien#endif
141550599Sobrien
141650599Sobrien/* List of dynamically allocates specs that have been defined so far.  */
141750599Sobrien
141890277Sobrienstatic struct spec_list *specs = (struct spec_list *) 0;
141990277Sobrien
142090277Sobrien/* Add appropriate libgcc specs to OBSTACK, taking into account
142190277Sobrien   various permutations of -shared-libgcc, -shared, and such.  */
142250599Sobrien
142390277Sobrien#ifdef ENABLE_SHARED_LIBGCC
142490277Sobrienstatic void
142590277Sobrieninit_gcc_specs (obstack, shared_name, static_name, eh_name)
142690277Sobrien     struct obstack *obstack;
142790277Sobrien     const char *shared_name;
142890277Sobrien     const char *static_name;
142990277Sobrien     const char *eh_name;
143090277Sobrien{
143190277Sobrien  char buffer[128];
143290277Sobrien  const char *p;
143390277Sobrien
143490277Sobrien  /* If we see -shared-libgcc, then use the shared version.  */
143590277Sobrien  sprintf (buffer, "%%{shared-libgcc:%s %s}", shared_name, static_name);
143690277Sobrien  obstack_grow (obstack, buffer, strlen (buffer));
143790277Sobrien  /* If we see -static-libgcc, then use the static version.  */
143890277Sobrien  sprintf (buffer, "%%{static-libgcc:%s %s}", static_name, eh_name);
143990277Sobrien  obstack_grow (obstack, buffer, strlen (buffer));
144090277Sobrien  /* Otherwise, if we see -shared, then use the shared version
144190277Sobrien     if using EH registration routines or static version without
144290277Sobrien     exception handling routines otherwise.  */
144390277Sobrien  p = "%{!shared-libgcc:%{!static-libgcc:%{shared:";
144490277Sobrien  obstack_grow (obstack, p, strlen (p));
144590277Sobrien#ifdef LINK_EH_SPEC
144690277Sobrien  sprintf (buffer, "%s}}}", static_name);
144790277Sobrien#else
144890277Sobrien  sprintf (buffer, "%s}}}", shared_name);
144990277Sobrien#endif
145090277Sobrien  obstack_grow (obstack, buffer, strlen (buffer));
145190277Sobrien  /* Otherwise, use the static version.  */
145290277Sobrien  sprintf (buffer,
145390277Sobrien	   "%%{!shared-libgcc:%%{!static-libgcc:%%{!shared:%s %s}}}",
145490277Sobrien	   static_name, eh_name);
145590277Sobrien  obstack_grow (obstack, buffer, strlen (buffer));
145690277Sobrien}
145790277Sobrien#endif /* ENABLE_SHARED_LIBGCC */
145890277Sobrien
145950599Sobrien/* Initialize the specs lookup routines.  */
146050599Sobrien
146150599Sobrienstatic void
146250599Sobrieninit_spec ()
146350599Sobrien{
146490277Sobrien  struct spec_list *next = (struct spec_list *) 0;
146590277Sobrien  struct spec_list *sl   = (struct spec_list *) 0;
146650599Sobrien  int i;
146750599Sobrien
146850599Sobrien  if (specs)
146990277Sobrien    return;			/* Already initialized.  */
147050599Sobrien
147150599Sobrien  if (verbose_flag)
147290277Sobrien    notice ("Using built-in specs.\n");
147350599Sobrien
147450599Sobrien#ifdef EXTRA_SPECS
147552520Sobrien  extra_specs = (struct spec_list *)
147690277Sobrien    xcalloc (sizeof (struct spec_list), ARRAY_SIZE (extra_specs_1));
147790277Sobrien
147890277Sobrien  for (i = ARRAY_SIZE (extra_specs_1) - 1; i >= 0; i--)
147950599Sobrien    {
148050599Sobrien      sl = &extra_specs[i];
148152520Sobrien      sl->name = extra_specs_1[i].name;
148252520Sobrien      sl->ptr = extra_specs_1[i].ptr;
148350599Sobrien      sl->next = next;
148450599Sobrien      sl->name_len = strlen (sl->name);
148550599Sobrien      sl->ptr_spec = &sl->ptr;
148650599Sobrien      next = sl;
148750599Sobrien    }
148850599Sobrien#endif
148950599Sobrien
149090277Sobrien  for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
149150599Sobrien    {
149250599Sobrien      sl = &static_specs[i];
149350599Sobrien      sl->next = next;
149450599Sobrien      next = sl;
149550599Sobrien    }
149650599Sobrien
149790277Sobrien#ifdef ENABLE_SHARED_LIBGCC
149890277Sobrien  /* ??? If neither -shared-libgcc nor --static-libgcc was
149990277Sobrien     seen, then we should be making an educated guess.  Some proposed
150090277Sobrien     heuristics for ELF include:
150190277Sobrien
150290277Sobrien	(1) If "-Wl,--export-dynamic", then it's a fair bet that the
150390277Sobrien	    program will be doing dynamic loading, which will likely
150490277Sobrien	    need the shared libgcc.
150590277Sobrien
150690277Sobrien	(2) If "-ldl", then it's also a fair bet that we're doing
150790277Sobrien	    dynamic loading.
150890277Sobrien
150990277Sobrien	(3) For each ET_DYN we're linking against (either through -lfoo
151090277Sobrien	    or /some/path/foo.so), check to see whether it or one of
151190277Sobrien	    its dependencies depends on a shared libgcc.
151290277Sobrien
151390277Sobrien	(4) If "-shared"
151490277Sobrien
151590277Sobrien	    If the runtime is fixed to look for program headers instead
151690277Sobrien	    of calling __register_frame_info at all, for each object,
151790277Sobrien	    use the shared libgcc if any EH symbol referenced.
151890277Sobrien
151990277Sobrien	    If crtstuff is fixed to not invoke __register_frame_info
152090277Sobrien	    automatically, for each object, use the shared libgcc if
152190277Sobrien	    any non-empty unwind section found.
152290277Sobrien
152390277Sobrien     Doing any of this probably requires invoking an external program to
152490277Sobrien     do the actual object file scanning.  */
152590277Sobrien  {
152690277Sobrien    const char *p = libgcc_spec;
152790277Sobrien    int in_sep = 1;
152890277Sobrien
152990277Sobrien    /* Transform the extant libgcc_spec into one that uses the shared libgcc
153090277Sobrien       when given the proper command line arguments.  */
153190277Sobrien    while (*p)
153290277Sobrien      {
153390277Sobrien        if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0)
153490277Sobrien	  {
153590277Sobrien	    init_gcc_specs (&obstack,
153690277Sobrien#ifdef NO_SHARED_LIBGCC_MULTILIB
153790277Sobrien			    "-lgcc_s"
153890277Sobrien#else
153990277Sobrien			    "-lgcc_s%M"
154090277Sobrien#endif
154190277Sobrien			    ,
154290277Sobrien			    "-lgcc",
154390277Sobrien			    "-lgcc_eh");
154490277Sobrien	    p += 5;
154590277Sobrien	    in_sep = 0;
154690277Sobrien	  }
154790277Sobrien	else if (in_sep && *p == 'l' && strncmp (p, "libgcc.a%s", 10) == 0)
154890277Sobrien	  {
154990277Sobrien	    /* Ug.  We don't know shared library extensions.  Hope that
155090277Sobrien	       systems that use this form don't do shared libraries.  */
155190277Sobrien	    init_gcc_specs (&obstack,
155290277Sobrien#ifdef NO_SHARED_LIBGCC_MULTILIB
155390277Sobrien			    "-lgcc_s"
155490277Sobrien#else
155590277Sobrien			    "-lgcc_s%M"
155690277Sobrien#endif
155790277Sobrien			    ,
155890277Sobrien			    "libgcc.a%s",
155990277Sobrien			    "libgcc_eh.a%s");
156090277Sobrien	    p += 10;
156190277Sobrien	    in_sep = 0;
156290277Sobrien	  }
156390277Sobrien	else
156490277Sobrien	  {
156590277Sobrien	    obstack_1grow (&obstack, *p);
156690277Sobrien	    in_sep = (*p == ' ');
156790277Sobrien	    p += 1;
156890277Sobrien	  }
156990277Sobrien      }
157090277Sobrien
157190277Sobrien    obstack_1grow (&obstack, '\0');
157290277Sobrien    libgcc_spec = obstack_finish (&obstack);
157390277Sobrien  }
157490277Sobrien#endif
157590277Sobrien#ifdef USE_AS_TRADITIONAL_FORMAT
157690277Sobrien  /* Prepend "--traditional-format" to whatever asm_spec we had before.  */
157790277Sobrien  {
157890277Sobrien    static const char tf[] = "--traditional-format ";
157990277Sobrien    obstack_grow (&obstack, tf, sizeof(tf) - 1);
158090277Sobrien    obstack_grow0 (&obstack, asm_spec, strlen (asm_spec));
158190277Sobrien    asm_spec = obstack_finish (&obstack);
158290277Sobrien  }
158390277Sobrien#endif
158490277Sobrien#ifdef LINK_EH_SPEC
158590277Sobrien  /* Prepend LINK_EH_SPEC to whatever link_spec we had before.  */
158690277Sobrien  obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1);
158790277Sobrien  obstack_grow0 (&obstack, link_spec, strlen (link_spec));
158890277Sobrien  link_spec = obstack_finish (&obstack);
158990277Sobrien#endif
159090277Sobrien
159150599Sobrien  specs = sl;
159250599Sobrien}
159350599Sobrien
159418334Speter/* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
159518334Speter   removed; If the spec starts with a + then SPEC is added to the end of the
159650599Sobrien   current spec.  */
159718334Speter
159818334Speterstatic void
159918334Speterset_spec (name, spec)
160052520Sobrien     const char *name;
160152520Sobrien     const char *spec;
160218334Speter{
160318334Speter  struct spec_list *sl;
160490277Sobrien  const char *old_spec;
160550599Sobrien  int name_len = strlen (name);
160650599Sobrien  int i;
160718334Speter
160890277Sobrien  /* If this is the first call, initialize the statically allocated specs.  */
160950599Sobrien  if (!specs)
161050599Sobrien    {
161190277Sobrien      struct spec_list *next = (struct spec_list *) 0;
161290277Sobrien      for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
161350599Sobrien	{
161450599Sobrien	  sl = &static_specs[i];
161550599Sobrien	  sl->next = next;
161650599Sobrien	  next = sl;
161750599Sobrien	}
161850599Sobrien      specs = sl;
161950599Sobrien    }
162050599Sobrien
162190277Sobrien  /* See if the spec already exists.  */
162218334Speter  for (sl = specs; sl; sl = sl->next)
162350599Sobrien    if (name_len == sl->name_len && !strcmp (sl->name, name))
162418334Speter      break;
162518334Speter
162618334Speter  if (!sl)
162718334Speter    {
162890277Sobrien      /* Not found - make it.  */
162918334Speter      sl = (struct spec_list *) xmalloc (sizeof (struct spec_list));
163090277Sobrien      sl->name = xstrdup (name);
163150599Sobrien      sl->name_len = name_len;
163250599Sobrien      sl->ptr_spec = &sl->ptr;
163350599Sobrien      sl->alloc_p = 0;
163450599Sobrien      *(sl->ptr_spec) = "";
163518334Speter      sl->next = specs;
163618334Speter      specs = sl;
163718334Speter    }
163818334Speter
163950599Sobrien  old_spec = *(sl->ptr_spec);
164052520Sobrien  *(sl->ptr_spec) = ((spec[0] == '+' && ISSPACE ((unsigned char)spec[1]))
164190277Sobrien		     ? concat (old_spec, spec + 1, NULL)
164290277Sobrien		     : xstrdup (spec));
164318334Speter
164450599Sobrien#ifdef DEBUG_SPECS
164550599Sobrien  if (verbose_flag)
164652520Sobrien    notice ("Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
164750599Sobrien#endif
164850599Sobrien
164990277Sobrien  /* Free the old spec.  */
165050599Sobrien  if (old_spec && sl->alloc_p)
165190277Sobrien    free ((PTR) old_spec);
165250599Sobrien
165350599Sobrien  sl->alloc_p = 1;
165418334Speter}
165518334Speter
165618334Speter/* Accumulate a command (program name and args), and run it.  */
165718334Speter
165818334Speter/* Vector of pointers to arguments in the current line of specifications.  */
165918334Speter
166090277Sobrienstatic const char **argbuf;
166118334Speter
166218334Speter/* Number of elements allocated in argbuf.  */
166318334Speter
166418334Speterstatic int argbuf_length;
166518334Speter
166618334Speter/* Number of elements in argbuf currently in use (containing args).  */
166718334Speter
166818334Speterstatic int argbuf_index;
166918334Speter
167090277Sobrien/* This is the list of suffixes and codes (%g/%u/%U/%j) and the associated
167190277Sobrien   temp file.  If the HOST_BIT_BUCKET is used for %j, no entry is made for
167290277Sobrien   it here.  */
167350599Sobrien
167418334Speterstatic struct temp_name {
167552520Sobrien  const char *suffix;	/* suffix associated with the code.  */
167618334Speter  int length;		/* strlen (suffix).  */
167718334Speter  int unique;		/* Indicates whether %g or %u/%U was used.  */
167852520Sobrien  const char *filename;	/* associated filename.  */
167918334Speter  int filename_length;	/* strlen (filename).  */
168018334Speter  struct temp_name *next;
168118334Speter} *temp_names;
168218334Speter
168318334Speter/* Number of commands executed so far.  */
168418334Speter
168518334Speterstatic int execution_count;
168618334Speter
168718334Speter/* Number of commands that exited with a signal.  */
168818334Speter
168918334Speterstatic int signal_count;
169018334Speter
169118334Speter/* Name with which this program was invoked.  */
169218334Speter
169352520Sobrienstatic const char *programname;
169418334Speter
169518334Speter/* Clear out the vector of arguments (after a command is executed).  */
169618334Speter
169718334Speterstatic void
169818334Speterclear_args ()
169918334Speter{
170018334Speter  argbuf_index = 0;
170118334Speter}
170218334Speter
170318334Speter/* Add one argument to the vector at the end.
170418334Speter   This is done when a space is seen or at the end of the line.
170518334Speter   If DELETE_ALWAYS is nonzero, the arg is a filename
170618334Speter    and the file should be deleted eventually.
170718334Speter   If DELETE_FAILURE is nonzero, the arg is a filename
170818334Speter    and the file should be deleted if this compilation fails.  */
170918334Speter
171018334Speterstatic void
171118334Speterstore_arg (arg, delete_always, delete_failure)
171290277Sobrien     const char *arg;
171318334Speter     int delete_always, delete_failure;
171418334Speter{
171518334Speter  if (argbuf_index + 1 == argbuf_length)
171650599Sobrien    argbuf
171790277Sobrien      = (const char **) xrealloc (argbuf,
171890277Sobrien				  (argbuf_length *= 2) * sizeof (const char *));
171918334Speter
172018334Speter  argbuf[argbuf_index++] = arg;
172118334Speter  argbuf[argbuf_index] = 0;
172218334Speter
172318334Speter  if (delete_always || delete_failure)
172418334Speter    record_temp_file (arg, delete_always, delete_failure);
172518334Speter}
172618334Speter
172790277Sobrien/* Load specs from a file name named FILENAME, replacing occurrences of
172890277Sobrien   various different types of line-endings, \r\n, \n\r and just \r, with
172990277Sobrien   a single \n.  */
173050599Sobrien
173190277Sobrienstatic char *
173290277Sobrienload_specs (filename)
173352520Sobrien     const char *filename;
173450599Sobrien{
173550599Sobrien  int desc;
173650599Sobrien  int readlen;
173750599Sobrien  struct stat statbuf;
173850599Sobrien  char *buffer;
173990277Sobrien  char *buffer_p;
174090277Sobrien  char *specs;
174190277Sobrien  char *specs_p;
174250599Sobrien
174350599Sobrien  if (verbose_flag)
174452520Sobrien    notice ("Reading specs from %s\n", filename);
174550599Sobrien
174650599Sobrien  /* Open and stat the file.  */
174750599Sobrien  desc = open (filename, O_RDONLY, 0);
174850599Sobrien  if (desc < 0)
174950599Sobrien    pfatal_with_name (filename);
175050599Sobrien  if (stat (filename, &statbuf) < 0)
175150599Sobrien    pfatal_with_name (filename);
175250599Sobrien
175350599Sobrien  /* Read contents of file into BUFFER.  */
175450599Sobrien  buffer = xmalloc ((unsigned) statbuf.st_size + 1);
175550599Sobrien  readlen = read (desc, buffer, (unsigned) statbuf.st_size);
175650599Sobrien  if (readlen < 0)
175750599Sobrien    pfatal_with_name (filename);
175850599Sobrien  buffer[readlen] = 0;
175950599Sobrien  close (desc);
176050599Sobrien
176190277Sobrien  specs = xmalloc (readlen + 1);
176290277Sobrien  specs_p = specs;
176390277Sobrien  for (buffer_p = buffer; buffer_p && *buffer_p; buffer_p++)
176490277Sobrien    {
176590277Sobrien      int skip = 0;
176690277Sobrien      char c = *buffer_p;
176790277Sobrien      if (c == '\r')
176890277Sobrien	{
176990277Sobrien	  if (buffer_p > buffer && *(buffer_p - 1) == '\n')	/* \n\r */
177090277Sobrien	    skip = 1;
177190277Sobrien	  else if (*(buffer_p + 1) == '\n')			/* \r\n */
177290277Sobrien	    skip = 1;
177390277Sobrien	  else							/* \r */
177490277Sobrien	    c = '\n';
177590277Sobrien	}
177690277Sobrien      if (! skip)
177790277Sobrien	*specs_p++ = c;
177890277Sobrien    }
177990277Sobrien  *specs_p = '\0';
178090277Sobrien
178190277Sobrien  free (buffer);
178290277Sobrien  return (specs);
178390277Sobrien}
178490277Sobrien
178590277Sobrien/* Read compilation specs from a file named FILENAME,
178690277Sobrien   replacing the default ones.
178790277Sobrien
178890277Sobrien   A suffix which starts with `*' is a definition for
178990277Sobrien   one of the machine-specific sub-specs.  The "suffix" should be
179090277Sobrien   *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
179190277Sobrien   The corresponding spec is stored in asm_spec, etc.,
179290277Sobrien   rather than in the `compilers' vector.
179390277Sobrien
179490277Sobrien   Anything invalid in the file is a fatal error.  */
179590277Sobrien
179690277Sobrienstatic void
179790277Sobrienread_specs (filename, main_p)
179890277Sobrien     const char *filename;
179990277Sobrien     int main_p;
180090277Sobrien{
180190277Sobrien  char *buffer;
180290277Sobrien  char *p;
180390277Sobrien
180490277Sobrien  buffer = load_specs (filename);
180590277Sobrien
180650599Sobrien  /* Scan BUFFER for specs, putting them in the vector.  */
180750599Sobrien  p = buffer;
180850599Sobrien  while (1)
180950599Sobrien    {
181050599Sobrien      char *suffix;
181150599Sobrien      char *spec;
181250599Sobrien      char *in, *out, *p1, *p2, *p3;
181350599Sobrien
181450599Sobrien      /* Advance P in BUFFER to the next nonblank nocomment line.  */
181550599Sobrien      p = skip_whitespace (p);
181650599Sobrien      if (*p == 0)
181750599Sobrien	break;
181850599Sobrien
181950599Sobrien      /* Is this a special command that starts with '%'? */
182050599Sobrien      /* Don't allow this for the main specs file, since it would
182150599Sobrien	 encourage people to overwrite it.  */
182250599Sobrien      if (*p == '%' && !main_p)
182350599Sobrien	{
182450599Sobrien	  p1 = p;
182550599Sobrien	  while (*p && *p != '\n')
182650599Sobrien	    p++;
182750599Sobrien
182890277Sobrien	  /* Skip '\n'.  */
182990277Sobrien	  p++;
183050599Sobrien
183190277Sobrien	  if (!strncmp (p1, "%include", sizeof ("%include") - 1)
183250599Sobrien	      && (p1[sizeof "%include" - 1] == ' '
183350599Sobrien		  || p1[sizeof "%include" - 1] == '\t'))
183450599Sobrien	    {
183550599Sobrien	      char *new_filename;
183650599Sobrien
183750599Sobrien	      p1 += sizeof ("%include");
183850599Sobrien	      while (*p1 == ' ' || *p1 == '\t')
183950599Sobrien		p1++;
184050599Sobrien
184150599Sobrien	      if (*p1++ != '<' || p[-2] != '>')
184252520Sobrien		fatal ("specs %%include syntax malformed after %ld characters",
184352520Sobrien		       (long) (p1 - buffer + 1));
184450599Sobrien
184550599Sobrien	      p[-2] = '\0';
184650599Sobrien	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
184750599Sobrien	      read_specs (new_filename ? new_filename : p1, FALSE);
184850599Sobrien	      continue;
184950599Sobrien	    }
185050599Sobrien	  else if (!strncmp (p1, "%include_noerr", sizeof "%include_noerr" - 1)
185150599Sobrien		   && (p1[sizeof "%include_noerr" - 1] == ' '
185250599Sobrien		       || p1[sizeof "%include_noerr" - 1] == '\t'))
185350599Sobrien	    {
185450599Sobrien	      char *new_filename;
185550599Sobrien
185650599Sobrien	      p1 += sizeof "%include_noerr";
185790277Sobrien	      while (*p1 == ' ' || *p1 == '\t')
185890277Sobrien		p1++;
185950599Sobrien
186050599Sobrien	      if (*p1++ != '<' || p[-2] != '>')
186152520Sobrien		fatal ("specs %%include syntax malformed after %ld characters",
186252520Sobrien		       (long) (p1 - buffer + 1));
186350599Sobrien
186450599Sobrien	      p[-2] = '\0';
186550599Sobrien	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
186650599Sobrien	      if (new_filename)
186750599Sobrien		read_specs (new_filename, FALSE);
186850599Sobrien	      else if (verbose_flag)
186990277Sobrien		notice ("could not find specs file %s\n", p1);
187050599Sobrien	      continue;
187150599Sobrien	    }
187250599Sobrien	  else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
187350599Sobrien		   && (p1[sizeof "%rename" - 1] == ' '
187450599Sobrien		       || p1[sizeof "%rename" - 1] == '\t'))
187550599Sobrien	    {
187650599Sobrien	      int name_len;
187750599Sobrien	      struct spec_list *sl;
187850599Sobrien
187950599Sobrien	      /* Get original name */
188050599Sobrien	      p1 += sizeof "%rename";
188150599Sobrien	      while (*p1 == ' ' || *p1 == '\t')
188250599Sobrien		p1++;
188350599Sobrien
188490277Sobrien	      if (! ISALPHA ((unsigned char) *p1))
188552520Sobrien		fatal ("specs %%rename syntax malformed after %ld characters",
188652520Sobrien		       (long) (p1 - buffer));
188750599Sobrien
188850599Sobrien	      p2 = p1;
188990277Sobrien	      while (*p2 && !ISSPACE ((unsigned char) *p2))
189050599Sobrien		p2++;
189150599Sobrien
189250599Sobrien	      if (*p2 != ' ' && *p2 != '\t')
189352520Sobrien		fatal ("specs %%rename syntax malformed after %ld characters",
189452520Sobrien		       (long) (p2 - buffer));
189550599Sobrien
189650599Sobrien	      name_len = p2 - p1;
189750599Sobrien	      *p2++ = '\0';
189850599Sobrien	      while (*p2 == ' ' || *p2 == '\t')
189950599Sobrien		p2++;
190050599Sobrien
190190277Sobrien	      if (! ISALPHA ((unsigned char) *p2))
190252520Sobrien		fatal ("specs %%rename syntax malformed after %ld characters",
190352520Sobrien		       (long) (p2 - buffer));
190450599Sobrien
190590277Sobrien	      /* Get new spec name.  */
190650599Sobrien	      p3 = p2;
190790277Sobrien	      while (*p3 && !ISSPACE ((unsigned char) *p3))
190850599Sobrien		p3++;
190950599Sobrien
191090277Sobrien	      if (p3 != p - 1)
191152520Sobrien		fatal ("specs %%rename syntax malformed after %ld characters",
191252520Sobrien		       (long) (p3 - buffer));
191350599Sobrien	      *p3 = '\0';
191450599Sobrien
191550599Sobrien	      for (sl = specs; sl; sl = sl->next)
191650599Sobrien		if (name_len == sl->name_len && !strcmp (sl->name, p1))
191750599Sobrien		  break;
191850599Sobrien
191950599Sobrien	      if (!sl)
192050599Sobrien		fatal ("specs %s spec was not found to be renamed", p1);
192150599Sobrien
192250599Sobrien	      if (strcmp (p1, p2) == 0)
192350599Sobrien		continue;
192450599Sobrien
192550599Sobrien	      if (verbose_flag)
192650599Sobrien		{
192752520Sobrien		  notice ("rename spec %s to %s\n", p1, p2);
192850599Sobrien#ifdef DEBUG_SPECS
192952520Sobrien		  notice ("spec is '%s'\n\n", *(sl->ptr_spec));
193050599Sobrien#endif
193150599Sobrien		}
193250599Sobrien
193350599Sobrien	      set_spec (p2, *(sl->ptr_spec));
193450599Sobrien	      if (sl->alloc_p)
193590277Sobrien		free ((PTR) *(sl->ptr_spec));
193650599Sobrien
193750599Sobrien	      *(sl->ptr_spec) = "";
193850599Sobrien	      sl->alloc_p = 0;
193950599Sobrien	      continue;
194050599Sobrien	    }
194150599Sobrien	  else
194252520Sobrien	    fatal ("specs unknown %% command after %ld characters",
194352520Sobrien		   (long) (p1 - buffer));
194450599Sobrien	}
194550599Sobrien
194650599Sobrien      /* Find the colon that should end the suffix.  */
194750599Sobrien      p1 = p;
194850599Sobrien      while (*p1 && *p1 != ':' && *p1 != '\n')
194950599Sobrien	p1++;
195050599Sobrien
195150599Sobrien      /* The colon shouldn't be missing.  */
195250599Sobrien      if (*p1 != ':')
195352520Sobrien	fatal ("specs file malformed after %ld characters",
195452520Sobrien	       (long) (p1 - buffer));
195550599Sobrien
195650599Sobrien      /* Skip back over trailing whitespace.  */
195750599Sobrien      p2 = p1;
195850599Sobrien      while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t'))
195950599Sobrien	p2--;
196050599Sobrien
196150599Sobrien      /* Copy the suffix to a string.  */
196250599Sobrien      suffix = save_string (p, p2 - p);
196350599Sobrien      /* Find the next line.  */
196450599Sobrien      p = skip_whitespace (p1 + 1);
196550599Sobrien      if (p[1] == 0)
196652520Sobrien	fatal ("specs file malformed after %ld characters",
196752520Sobrien	       (long) (p - buffer));
196850599Sobrien
196950599Sobrien      p1 = p;
197050599Sobrien      /* Find next blank line or end of string.  */
197150599Sobrien      while (*p1 && !(*p1 == '\n' && (p1[1] == '\n' || p1[1] == '\0')))
197250599Sobrien	p1++;
197350599Sobrien
197450599Sobrien      /* Specs end at the blank line and do not include the newline.  */
197550599Sobrien      spec = save_string (p, p1 - p);
197650599Sobrien      p = p1;
197750599Sobrien
197850599Sobrien      /* Delete backslash-newline sequences from the spec.  */
197950599Sobrien      in = spec;
198050599Sobrien      out = spec;
198150599Sobrien      while (*in != 0)
198250599Sobrien	{
198350599Sobrien	  if (in[0] == '\\' && in[1] == '\n')
198450599Sobrien	    in += 2;
198550599Sobrien	  else if (in[0] == '#')
198650599Sobrien	    while (*in && *in != '\n')
198750599Sobrien	      in++;
198850599Sobrien
198950599Sobrien	  else
199050599Sobrien	    *out++ = *in++;
199150599Sobrien	}
199250599Sobrien      *out = 0;
199350599Sobrien
199450599Sobrien      if (suffix[0] == '*')
199550599Sobrien	{
199650599Sobrien	  if (! strcmp (suffix, "*link_command"))
199750599Sobrien	    link_command_spec = spec;
199850599Sobrien	  else
199950599Sobrien	    set_spec (suffix + 1, spec);
200050599Sobrien	}
200150599Sobrien      else
200250599Sobrien	{
200350599Sobrien	  /* Add this pair to the vector.  */
200450599Sobrien	  compilers
200550599Sobrien	    = ((struct compiler *)
200650599Sobrien	       xrealloc (compilers,
200750599Sobrien			 (n_compilers + 2) * sizeof (struct compiler)));
200850599Sobrien
200950599Sobrien	  compilers[n_compilers].suffix = suffix;
201090277Sobrien	  compilers[n_compilers].spec = spec;
201150599Sobrien	  n_compilers++;
201290277Sobrien	  memset (&compilers[n_compilers], 0, sizeof compilers[n_compilers]);
201350599Sobrien	}
201450599Sobrien
201550599Sobrien      if (*suffix == 0)
201650599Sobrien	link_command_spec = spec;
201750599Sobrien    }
201850599Sobrien
201950599Sobrien  if (link_command_spec == 0)
202050599Sobrien    fatal ("spec file has no spec for linking");
202150599Sobrien}
202250599Sobrien
202318334Speter/* Record the names of temporary files we tell compilers to write,
202418334Speter   and delete them at the end of the run.  */
202518334Speter
202618334Speter/* This is the common prefix we use to make temp file names.
202718334Speter   It is chosen once for each run of this program.
202890277Sobrien   It is substituted into a spec by %g or %j.
202918334Speter   Thus, all temp file names contain this prefix.
203018334Speter   In practice, all temp file names start with this prefix.
203118334Speter
203218334Speter   This prefix comes from the envvar TMPDIR if it is defined;
203318334Speter   otherwise, from the P_tmpdir macro if that is defined;
203450599Sobrien   otherwise, in /usr/tmp or /tmp;
203550599Sobrien   or finally the current directory if all else fails.  */
203618334Speter
203752520Sobrienstatic const char *temp_filename;
203818334Speter
203918334Speter/* Length of the prefix.  */
204018334Speter
204118334Speterstatic int temp_filename_length;
204218334Speter
204318334Speter/* Define the list of temporary files to delete.  */
204418334Speter
204518334Speterstruct temp_file
204618334Speter{
204752520Sobrien  const char *name;
204818334Speter  struct temp_file *next;
204918334Speter};
205018334Speter
205118334Speter/* Queue of files to delete on success or failure of compilation.  */
205218334Speterstatic struct temp_file *always_delete_queue;
205318334Speter/* Queue of files to delete on failure of compilation.  */
205418334Speterstatic struct temp_file *failure_delete_queue;
205518334Speter
205618334Speter/* Record FILENAME as a file to be deleted automatically.
205718334Speter   ALWAYS_DELETE nonzero means delete it if all compilation succeeds;
205818334Speter   otherwise delete it in any case.
205918334Speter   FAIL_DELETE nonzero means delete it if a compilation step fails;
206018334Speter   otherwise delete it in any case.  */
206118334Speter
206290277Sobrienvoid
206318334Speterrecord_temp_file (filename, always_delete, fail_delete)
206452520Sobrien     const char *filename;
206518334Speter     int always_delete;
206618334Speter     int fail_delete;
206718334Speter{
206890277Sobrien  char *const name = xstrdup (filename);
206918334Speter
207018334Speter  if (always_delete)
207118334Speter    {
207290277Sobrien      struct temp_file *temp;
207318334Speter      for (temp = always_delete_queue; temp; temp = temp->next)
207418334Speter	if (! strcmp (name, temp->name))
207518334Speter	  goto already1;
207650599Sobrien
207718334Speter      temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
207818334Speter      temp->next = always_delete_queue;
207918334Speter      temp->name = name;
208018334Speter      always_delete_queue = temp;
208150599Sobrien
208218334Speter    already1:;
208318334Speter    }
208418334Speter
208518334Speter  if (fail_delete)
208618334Speter    {
208790277Sobrien      struct temp_file *temp;
208818334Speter      for (temp = failure_delete_queue; temp; temp = temp->next)
208918334Speter	if (! strcmp (name, temp->name))
209018334Speter	  goto already2;
209150599Sobrien
209218334Speter      temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
209318334Speter      temp->next = failure_delete_queue;
209418334Speter      temp->name = name;
209518334Speter      failure_delete_queue = temp;
209650599Sobrien
209718334Speter    already2:;
209818334Speter    }
209918334Speter}
210018334Speter
210118334Speter/* Delete all the temporary files whose names we previously recorded.  */
210218334Speter
210318334Speterstatic void
210418334Speterdelete_if_ordinary (name)
210552520Sobrien     const char *name;
210618334Speter{
210718334Speter  struct stat st;
210818334Speter#ifdef DEBUG
210918334Speter  int i, c;
211018334Speter
211118334Speter  printf ("Delete %s? (y or n) ", name);
211218334Speter  fflush (stdout);
211318334Speter  i = getchar ();
211418334Speter  if (i != '\n')
211550599Sobrien    while ((c = getchar ()) != '\n' && c != EOF)
211650599Sobrien      ;
211750599Sobrien
211818334Speter  if (i == 'y' || i == 'Y')
211918334Speter#endif /* DEBUG */
212018334Speter    if (stat (name, &st) >= 0 && S_ISREG (st.st_mode))
212118334Speter      if (unlink (name) < 0)
212218334Speter	if (verbose_flag)
212318334Speter	  perror_with_name (name);
212418334Speter}
212518334Speter
212618334Speterstatic void
212718334Speterdelete_temp_files ()
212818334Speter{
212990277Sobrien  struct temp_file *temp;
213018334Speter
213118334Speter  for (temp = always_delete_queue; temp; temp = temp->next)
213218334Speter    delete_if_ordinary (temp->name);
213318334Speter  always_delete_queue = 0;
213418334Speter}
213518334Speter
213618334Speter/* Delete all the files to be deleted on error.  */
213718334Speter
213818334Speterstatic void
213918334Speterdelete_failure_queue ()
214018334Speter{
214190277Sobrien  struct temp_file *temp;
214218334Speter
214318334Speter  for (temp = failure_delete_queue; temp; temp = temp->next)
214418334Speter    delete_if_ordinary (temp->name);
214518334Speter}
214618334Speter
214718334Speterstatic void
214818334Speterclear_failure_queue ()
214918334Speter{
215018334Speter  failure_delete_queue = 0;
215118334Speter}
215218334Speter
215318334Speter/* Build a list of search directories from PATHS.
215418334Speter   PREFIX is a string to prepend to the list.
215518334Speter   If CHECK_DIR_P is non-zero we ensure the directory exists.
215618334Speter   This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
215718334Speter   It is also used by the --print-search-dirs flag.  */
215818334Speter
215918334Speterstatic char *
216018334Speterbuild_search_list (paths, prefix, check_dir_p)
216118334Speter     struct path_prefix *paths;
216252520Sobrien     const char *prefix;
216318334Speter     int check_dir_p;
216418334Speter{
216518334Speter  int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
216618334Speter  int just_suffix_len
216718334Speter    = (just_machine_suffix) ? strlen (just_machine_suffix) : 0;
216818334Speter  int first_time = TRUE;
216918334Speter  struct prefix_list *pprefix;
217018334Speter
217118334Speter  obstack_grow (&collect_obstack, prefix, strlen (prefix));
217290277Sobrien  obstack_1grow (&collect_obstack, '=');
217318334Speter
217418334Speter  for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
217518334Speter    {
217618334Speter      int len = strlen (pprefix->prefix);
217718334Speter
217818334Speter      if (machine_suffix
217950599Sobrien	  && (! check_dir_p
218018334Speter	      || is_directory (pprefix->prefix, machine_suffix, 0)))
218118334Speter	{
218218334Speter	  if (!first_time)
218318334Speter	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
218490277Sobrien
218518334Speter	  first_time = FALSE;
218618334Speter	  obstack_grow (&collect_obstack, pprefix->prefix, len);
218718334Speter	  obstack_grow (&collect_obstack, machine_suffix, suffix_len);
218818334Speter	}
218918334Speter
219018334Speter      if (just_machine_suffix
219118334Speter	  && pprefix->require_machine_suffix == 2
219250599Sobrien	  && (! check_dir_p
219318334Speter	      || is_directory (pprefix->prefix, just_machine_suffix, 0)))
219418334Speter	{
219550599Sobrien	  if (! first_time)
219618334Speter	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
219790277Sobrien
219818334Speter	  first_time = FALSE;
219918334Speter	  obstack_grow (&collect_obstack, pprefix->prefix, len);
220018334Speter	  obstack_grow (&collect_obstack, just_machine_suffix,
220118334Speter			just_suffix_len);
220218334Speter	}
220318334Speter
220450599Sobrien      if (! pprefix->require_machine_suffix)
220518334Speter	{
220650599Sobrien	  if (! first_time)
220718334Speter	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
220818334Speter
220918334Speter	  first_time = FALSE;
221018334Speter	  obstack_grow (&collect_obstack, pprefix->prefix, len);
221118334Speter	}
221218334Speter    }
221350599Sobrien
221418334Speter  obstack_1grow (&collect_obstack, '\0');
221518334Speter  return obstack_finish (&collect_obstack);
221618334Speter}
221718334Speter
221850599Sobrien/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
221950599Sobrien   for collect.  */
222018334Speter
222118334Speterstatic void
222218334Speterputenv_from_prefixes (paths, env_var)
222318334Speter     struct path_prefix *paths;
222452520Sobrien     const char *env_var;
222518334Speter{
222618334Speter  putenv (build_search_list (paths, env_var, 1));
222718334Speter}
222818334Speter
222990277Sobrien#ifndef VMS
223090277Sobrien
223190277Sobrien/* FIXME: the location independence code for VMS is hairier than this,
223290277Sobrien   and hasn't been written.  */
223390277Sobrien
223490277Sobrien/* Split a filename into component directories.  */
223590277Sobrien
223690277Sobrienstatic char **
223790277Sobriensplit_directories (name, ptr_num_dirs)
223890277Sobrien     const char *name;
223990277Sobrien     int *ptr_num_dirs;
224090277Sobrien{
224190277Sobrien  int num_dirs = 0;
224290277Sobrien  char **dirs;
224390277Sobrien  const char *p, *q;
224490277Sobrien  int ch;
224590277Sobrien
224690277Sobrien  /* Count the number of directories.  Special case MSDOS disk names as part
224790277Sobrien     of the initial directory.  */
224890277Sobrien  p = name;
224990277Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
225090277Sobrien  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
225190277Sobrien    {
225290277Sobrien      p += 3;
225390277Sobrien      num_dirs++;
225490277Sobrien    }
225590277Sobrien#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
225690277Sobrien
225790277Sobrien  while ((ch = *p++) != '\0')
225890277Sobrien    {
225990277Sobrien      if (IS_DIR_SEPARATOR (ch))
226090277Sobrien	{
226190277Sobrien	  num_dirs++;
226290277Sobrien	  while (IS_DIR_SEPARATOR (*p))
226390277Sobrien	    p++;
226490277Sobrien	}
226590277Sobrien    }
226690277Sobrien
226790277Sobrien  dirs = (char **) xmalloc (sizeof (char *) * (num_dirs + 2));
226890277Sobrien
226990277Sobrien  /* Now copy the directory parts.  */
227090277Sobrien  num_dirs = 0;
227190277Sobrien  p = name;
227290277Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
227390277Sobrien  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
227490277Sobrien    {
227590277Sobrien      dirs[num_dirs++] = save_string (p, 3);
227690277Sobrien      p += 3;
227790277Sobrien    }
227890277Sobrien#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
227990277Sobrien
228090277Sobrien  q = p;
228190277Sobrien  while ((ch = *p++) != '\0')
228290277Sobrien    {
228390277Sobrien      if (IS_DIR_SEPARATOR (ch))
228490277Sobrien	{
228590277Sobrien	  while (IS_DIR_SEPARATOR (*p))
228690277Sobrien	    p++;
228790277Sobrien
228890277Sobrien	  dirs[num_dirs++] = save_string (q, p - q);
228990277Sobrien	  q = p;
229090277Sobrien	}
229190277Sobrien    }
229290277Sobrien
229390277Sobrien  if (p - 1 - q > 0)
229490277Sobrien    dirs[num_dirs++] = save_string (q, p - 1 - q);
229590277Sobrien
229690277Sobrien  dirs[num_dirs] = NULL;
229790277Sobrien  if (ptr_num_dirs)
229890277Sobrien    *ptr_num_dirs = num_dirs;
229990277Sobrien
230090277Sobrien  return dirs;
230190277Sobrien}
230290277Sobrien
230390277Sobrien/* Release storage held by split directories.  */
230490277Sobrien
230590277Sobrienstatic void
230690277Sobrienfree_split_directories (dirs)
230790277Sobrien     char **dirs;
230890277Sobrien{
230990277Sobrien  int i = 0;
231090277Sobrien
231190277Sobrien  while (dirs[i] != NULL)
231290277Sobrien    free (dirs[i++]);
231390277Sobrien
231490277Sobrien  free ((char *) dirs);
231590277Sobrien}
231690277Sobrien
231790277Sobrien/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
231890277Sobrien   to PREFIX starting with the directory portion of PROGNAME and a relative
231990277Sobrien   pathname of the difference between BIN_PREFIX and PREFIX.
232090277Sobrien
232190277Sobrien   For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
232290277Sobrien   /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
232390277Sobrien   function will return /red/green/blue/../omega.
232490277Sobrien
232590277Sobrien   If no relative prefix can be found, return NULL.  */
232690277Sobrien
232790277Sobrienstatic char *
232890277Sobrienmake_relative_prefix (progname, bin_prefix, prefix)
232990277Sobrien     const char *progname;
233090277Sobrien     const char *bin_prefix;
233190277Sobrien     const char *prefix;
233290277Sobrien{
233390277Sobrien  char **prog_dirs, **bin_dirs, **prefix_dirs;
233490277Sobrien  int prog_num, bin_num, prefix_num, std_loc_p;
233590277Sobrien  int i, n, common;
233690277Sobrien
233790277Sobrien  prog_dirs = split_directories (progname, &prog_num);
233890277Sobrien  bin_dirs = split_directories (bin_prefix, &bin_num);
233990277Sobrien
234090277Sobrien  /* If there is no full pathname, try to find the program by checking in each
234190277Sobrien     of the directories specified in the PATH environment variable.  */
234290277Sobrien  if (prog_num == 1)
234390277Sobrien    {
234490277Sobrien      char *temp;
234590277Sobrien
234690277Sobrien      GET_ENV_PATH_LIST (temp, "PATH");
234790277Sobrien      if (temp)
234890277Sobrien	{
234990277Sobrien	  char *startp, *endp, *nstore;
235090277Sobrien	  size_t prefixlen = strlen (temp) + 1;
235190277Sobrien	  if (prefixlen < 2)
235290277Sobrien	    prefixlen = 2;
235390277Sobrien
235490277Sobrien	  nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
235590277Sobrien
235690277Sobrien	  startp = endp = temp;
235790277Sobrien	  while (1)
235890277Sobrien	    {
235990277Sobrien	      if (*endp == PATH_SEPARATOR || *endp == 0)
236090277Sobrien		{
236190277Sobrien		  if (endp == startp)
236290277Sobrien		    {
236390277Sobrien		      nstore[0] = '.';
236490277Sobrien		      nstore[1] = DIR_SEPARATOR;
236590277Sobrien		      nstore[2] = '\0';
236690277Sobrien		    }
236790277Sobrien		  else
236890277Sobrien		    {
236990277Sobrien		      strncpy (nstore, startp, endp - startp);
237090277Sobrien		      if (! IS_DIR_SEPARATOR (endp[-1]))
237190277Sobrien			{
237290277Sobrien			  nstore[endp - startp] = DIR_SEPARATOR;
237390277Sobrien			  nstore[endp - startp + 1] = 0;
237490277Sobrien			}
237590277Sobrien		      else
237690277Sobrien			nstore[endp - startp] = 0;
237790277Sobrien		    }
237890277Sobrien		  strcat (nstore, progname);
237990277Sobrien		  if (! access (nstore, X_OK)
238090277Sobrien#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
238190277Sobrien                      || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
238290277Sobrien#endif
238390277Sobrien		      )
238490277Sobrien		    {
238590277Sobrien		      free_split_directories (prog_dirs);
238690277Sobrien		      progname = nstore;
238790277Sobrien		      prog_dirs = split_directories (progname, &prog_num);
238890277Sobrien		      break;
238990277Sobrien		    }
239090277Sobrien
239190277Sobrien		  if (*endp == 0)
239290277Sobrien		    break;
239390277Sobrien		  endp = startp = endp + 1;
239490277Sobrien		}
239590277Sobrien	      else
239690277Sobrien		endp++;
239790277Sobrien	    }
239890277Sobrien	}
239990277Sobrien    }
240090277Sobrien
240190277Sobrien  /* Remove the program name from comparison of directory names.  */
240290277Sobrien  prog_num--;
240390277Sobrien
240490277Sobrien  /* Determine if the compiler is installed in the standard location, and if
240590277Sobrien     so, we don't need to specify relative directories.  Also, if argv[0]
240690277Sobrien     doesn't contain any directory specifiers, there is not much we can do.  */
240790277Sobrien  std_loc_p = 0;
240890277Sobrien  if (prog_num == bin_num)
240990277Sobrien    {
241090277Sobrien      for (i = 0; i < bin_num; i++)
241190277Sobrien	{
241290277Sobrien	  if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
241390277Sobrien	    break;
241490277Sobrien	}
241590277Sobrien
241690277Sobrien      if (prog_num <= 0 || i == bin_num)
241790277Sobrien	{
241890277Sobrien	  std_loc_p = 1;
241990277Sobrien	  free_split_directories (prog_dirs);
242090277Sobrien	  free_split_directories (bin_dirs);
242190277Sobrien	  prog_dirs = bin_dirs = (char **) 0;
242290277Sobrien	  return NULL;
242390277Sobrien	}
242490277Sobrien    }
242590277Sobrien
242690277Sobrien  prefix_dirs = split_directories (prefix, &prefix_num);
242790277Sobrien
242890277Sobrien  /* Find how many directories are in common between bin_prefix & prefix.  */
242990277Sobrien  n = (prefix_num < bin_num) ? prefix_num : bin_num;
243090277Sobrien  for (common = 0; common < n; common++)
243190277Sobrien    {
243290277Sobrien      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
243390277Sobrien	break;
243490277Sobrien    }
243590277Sobrien
243690277Sobrien  /* If there are no common directories, there can be no relative prefix.  */
243790277Sobrien  if (common == 0)
243890277Sobrien    {
243990277Sobrien      free_split_directories (prog_dirs);
244090277Sobrien      free_split_directories (bin_dirs);
244190277Sobrien      free_split_directories (prefix_dirs);
244290277Sobrien      return NULL;
244390277Sobrien    }
244490277Sobrien
244590277Sobrien  /* Build up the pathnames in argv[0].  */
244690277Sobrien  for (i = 0; i < prog_num; i++)
244790277Sobrien    obstack_grow (&obstack, prog_dirs[i], strlen (prog_dirs[i]));
244890277Sobrien
244990277Sobrien  /* Now build up the ..'s.  */
245090277Sobrien  for (i = common; i < n; i++)
245190277Sobrien    {
245290277Sobrien      obstack_grow (&obstack, DIR_UP, sizeof (DIR_UP) - 1);
245390277Sobrien      obstack_1grow (&obstack, DIR_SEPARATOR);
245490277Sobrien    }
245590277Sobrien
245690277Sobrien  /* Put in directories to move over to prefix.  */
245790277Sobrien  for (i = common; i < prefix_num; i++)
245890277Sobrien    obstack_grow (&obstack, prefix_dirs[i], strlen (prefix_dirs[i]));
245990277Sobrien
246090277Sobrien  free_split_directories (prog_dirs);
246190277Sobrien  free_split_directories (bin_dirs);
246290277Sobrien  free_split_directories (prefix_dirs);
246390277Sobrien
246490277Sobrien  obstack_1grow (&obstack, '\0');
246590277Sobrien  return obstack_finish (&obstack);
246690277Sobrien}
246790277Sobrien#endif /* VMS */
246890277Sobrien
246990277Sobrien/* Check whether NAME can be accessed in MODE.  This is like access,
247090277Sobrien   except that it never considers directories to be executable.  */
247190277Sobrien
247290277Sobrienstatic int
247390277Sobrienaccess_check (name, mode)
247490277Sobrien     const char *name;
247590277Sobrien     int mode;
247690277Sobrien{
247790277Sobrien  if (mode == X_OK)
247890277Sobrien    {
247990277Sobrien      struct stat st;
248090277Sobrien
248190277Sobrien      if (stat (name, &st) < 0
248290277Sobrien	  || S_ISDIR (st.st_mode))
248390277Sobrien	return -1;
248490277Sobrien    }
248590277Sobrien
248690277Sobrien  return access (name, mode);
248790277Sobrien}
248890277Sobrien
248918334Speter/* Search for NAME using the prefix list PREFIXES.  MODE is passed to
249018334Speter   access to check permissions.
249150599Sobrien   Return 0 if not found, otherwise return its name, allocated with malloc.  */
249218334Speter
249318334Speterstatic char *
249418334Speterfind_a_file (pprefix, name, mode)
249518334Speter     struct path_prefix *pprefix;
249652520Sobrien     const char *name;
249718334Speter     int mode;
249818334Speter{
249918334Speter  char *temp;
250090277Sobrien  const char *const file_suffix =
250190277Sobrien    ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "");
250218334Speter  struct prefix_list *pl;
250318334Speter  int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
250418334Speter
250552520Sobrien#ifdef DEFAULT_ASSEMBLER
250690277Sobrien  if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
250790277Sobrien    return xstrdup (DEFAULT_ASSEMBLER);
250852520Sobrien#endif
250952520Sobrien
251052520Sobrien#ifdef DEFAULT_LINKER
251190277Sobrien  if (! strcmp(name, "ld") && access (DEFAULT_LINKER, mode) == 0)
251290277Sobrien    return xstrdup (DEFAULT_LINKER);
251352520Sobrien#endif
251452520Sobrien
251518334Speter  if (machine_suffix)
251618334Speter    len += strlen (machine_suffix);
251718334Speter
251818334Speter  temp = xmalloc (len);
251918334Speter
252018334Speter  /* Determine the filename to execute (special case for absolute paths).  */
252118334Speter
252290277Sobrien  if (IS_ABSOLUTE_PATHNAME (name))
252318334Speter    {
252452520Sobrien      if (access (name, mode) == 0)
252518334Speter	{
252618334Speter	  strcpy (temp, name);
252718334Speter	  return temp;
252818334Speter	}
252918334Speter    }
253018334Speter  else
253118334Speter    for (pl = pprefix->plist; pl; pl = pl->next)
253218334Speter      {
253318334Speter	if (machine_suffix)
253418334Speter	  {
253518334Speter	    /* Some systems have a suffix for executable files.
253618334Speter	       So try appending that first.  */
253718334Speter	    if (file_suffix[0] != 0)
253818334Speter	      {
253918334Speter		strcpy (temp, pl->prefix);
254018334Speter		strcat (temp, machine_suffix);
254118334Speter		strcat (temp, name);
254218334Speter		strcat (temp, file_suffix);
254390277Sobrien		if (access_check (temp, mode) == 0)
254418334Speter		  {
254518334Speter		    if (pl->used_flag_ptr != 0)
254618334Speter		      *pl->used_flag_ptr = 1;
254718334Speter		    return temp;
254818334Speter		  }
254918334Speter	      }
255018334Speter
255118334Speter	    /* Now try just the name.  */
255218334Speter	    strcpy (temp, pl->prefix);
255318334Speter	    strcat (temp, machine_suffix);
255418334Speter	    strcat (temp, name);
255590277Sobrien	    if (access_check (temp, mode) == 0)
255618334Speter	      {
255718334Speter		if (pl->used_flag_ptr != 0)
255818334Speter		  *pl->used_flag_ptr = 1;
255918334Speter		return temp;
256018334Speter	      }
256118334Speter	  }
256218334Speter
256318334Speter	/* Certain prefixes are tried with just the machine type,
256418334Speter	   not the version.  This is used for finding as, ld, etc.  */
256518334Speter	if (just_machine_suffix && pl->require_machine_suffix == 2)
256618334Speter	  {
256718334Speter	    /* Some systems have a suffix for executable files.
256818334Speter	       So try appending that first.  */
256918334Speter	    if (file_suffix[0] != 0)
257018334Speter	      {
257118334Speter		strcpy (temp, pl->prefix);
257218334Speter		strcat (temp, just_machine_suffix);
257318334Speter		strcat (temp, name);
257418334Speter		strcat (temp, file_suffix);
257590277Sobrien		if (access_check (temp, mode) == 0)
257618334Speter		  {
257718334Speter		    if (pl->used_flag_ptr != 0)
257818334Speter		      *pl->used_flag_ptr = 1;
257918334Speter		    return temp;
258018334Speter		  }
258118334Speter	      }
258218334Speter
258318334Speter	    strcpy (temp, pl->prefix);
258418334Speter	    strcat (temp, just_machine_suffix);
258518334Speter	    strcat (temp, name);
258690277Sobrien	    if (access_check (temp, mode) == 0)
258718334Speter	      {
258818334Speter		if (pl->used_flag_ptr != 0)
258918334Speter		  *pl->used_flag_ptr = 1;
259018334Speter		return temp;
259118334Speter	      }
259218334Speter	  }
259318334Speter
259418334Speter	/* Certain prefixes can't be used without the machine suffix
259518334Speter	   when the machine or version is explicitly specified.  */
259650599Sobrien	if (! pl->require_machine_suffix)
259718334Speter	  {
259818334Speter	    /* Some systems have a suffix for executable files.
259918334Speter	       So try appending that first.  */
260018334Speter	    if (file_suffix[0] != 0)
260118334Speter	      {
260218334Speter		strcpy (temp, pl->prefix);
260318334Speter		strcat (temp, name);
260418334Speter		strcat (temp, file_suffix);
260590277Sobrien		if (access_check (temp, mode) == 0)
260618334Speter		  {
260718334Speter		    if (pl->used_flag_ptr != 0)
260818334Speter		      *pl->used_flag_ptr = 1;
260918334Speter		    return temp;
261018334Speter		  }
261118334Speter	      }
261218334Speter
261318334Speter	    strcpy (temp, pl->prefix);
261418334Speter	    strcat (temp, name);
261590277Sobrien	    if (access_check (temp, mode) == 0)
261618334Speter	      {
261718334Speter		if (pl->used_flag_ptr != 0)
261818334Speter		  *pl->used_flag_ptr = 1;
261918334Speter		return temp;
262018334Speter	      }
262118334Speter	  }
262218334Speter      }
262318334Speter
262418334Speter  free (temp);
262518334Speter  return 0;
262618334Speter}
262718334Speter
262890277Sobrien/* Ranking of prefixes in the sort list. -B prefixes are put before
262990277Sobrien   all others.  */
263018334Speter
263190277Sobrienenum path_prefix_priority
263290277Sobrien{
263390277Sobrien  PREFIX_PRIORITY_B_OPT,
263490277Sobrien  PREFIX_PRIORITY_LAST
263590277Sobrien};
263690277Sobrien
263790277Sobrien/* Add an entry for PREFIX in PLIST.  The PLIST is kept in assending
263890277Sobrien   order according to PRIORITY.  Within each PRIORITY, new entries are
263990277Sobrien   appended.
264090277Sobrien
264118334Speter   If WARN is nonzero, we will warn if no file is found
264218334Speter   through this prefix.  WARN should point to an int
264318334Speter   which will be set to 1 if this entry is used.
264418334Speter
264550599Sobrien   COMPONENT is the value to be passed to update_path.
264650599Sobrien
264718334Speter   REQUIRE_MACHINE_SUFFIX is 1 if this prefix can't be used without
264818334Speter   the complete value of machine_suffix.
264918334Speter   2 means try both machine_suffix and just_machine_suffix.  */
265018334Speter
265118334Speterstatic void
265290277Sobrienadd_prefix (pprefix, prefix, component, priority, require_machine_suffix, warn)
265318334Speter     struct path_prefix *pprefix;
265452520Sobrien     const char *prefix;
265552520Sobrien     const char *component;
265690277Sobrien     /* enum prefix_priority */ int priority;
265718334Speter     int require_machine_suffix;
265818334Speter     int *warn;
265918334Speter{
266018334Speter  struct prefix_list *pl, **prev;
266118334Speter  int len;
266218334Speter
266390277Sobrien  for (prev = &pprefix->plist;
266490277Sobrien       (*prev) != NULL && (*prev)->priority <= priority;
266590277Sobrien       prev = &(*prev)->next)
266690277Sobrien    ;
266718334Speter
266818334Speter  /* Keep track of the longest prefix */
266918334Speter
267050599Sobrien  prefix = update_path (prefix, component);
267118334Speter  len = strlen (prefix);
267218334Speter  if (len > pprefix->max_len)
267318334Speter    pprefix->max_len = len;
267418334Speter
267518334Speter  pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list));
267690277Sobrien  pl->prefix = prefix;
267718334Speter  pl->require_machine_suffix = require_machine_suffix;
267818334Speter  pl->used_flag_ptr = warn;
267990277Sobrien  pl->priority = priority;
268018334Speter  if (warn)
268118334Speter    *warn = 0;
268218334Speter
268390277Sobrien  /* Insert after PREV */
268490277Sobrien  pl->next = (*prev);
268590277Sobrien  (*prev) = pl;
268618334Speter}
268718334Speter
268818334Speter/* Execute the command specified by the arguments on the current line of spec.
268918334Speter   When using pipes, this includes several piped-together commands
269018334Speter   with `|' between them.
269118334Speter
269218334Speter   Return 0 if successful, -1 if failed.  */
269318334Speter
269418334Speterstatic int
269518334Speterexecute ()
269618334Speter{
269718334Speter  int i;
269818334Speter  int n_commands;		/* # of command.  */
269918334Speter  char *string;
270018334Speter  struct command
270190277Sobrien  {
270290277Sobrien    const char *prog;		/* program name.  */
270390277Sobrien    const char **argv;		/* vector of args.  */
270490277Sobrien    int pid;			/* pid of process for this command.  */
270590277Sobrien  };
270618334Speter
270718334Speter  struct command *commands;	/* each command buffer with above info.  */
270818334Speter
270918334Speter  /* Count # of piped commands.  */
271018334Speter  for (n_commands = 1, i = 0; i < argbuf_index; i++)
271118334Speter    if (strcmp (argbuf[i], "|") == 0)
271218334Speter      n_commands++;
271318334Speter
271418334Speter  /* Get storage for each command.  */
271590277Sobrien  commands = (struct command *) alloca (n_commands * sizeof (struct command));
271618334Speter
271718334Speter  /* Split argbuf into its separate piped processes,
271818334Speter     and record info about each one.
271918334Speter     Also search for the programs that are to be run.  */
272018334Speter
272118334Speter  commands[0].prog = argbuf[0]; /* first command.  */
272218334Speter  commands[0].argv = &argbuf[0];
272318334Speter  string = find_a_file (&exec_prefixes, commands[0].prog, X_OK);
272450599Sobrien
272518334Speter  if (string)
272618334Speter    commands[0].argv[0] = string;
272718334Speter
272818334Speter  for (n_commands = 1, i = 0; i < argbuf_index; i++)
272918334Speter    if (strcmp (argbuf[i], "|") == 0)
273018334Speter      {				/* each command.  */
273152520Sobrien#if defined (__MSDOS__) || defined (OS2) || defined (VMS)
273290277Sobrien	fatal ("-pipe not supported");
273318334Speter#endif
273418334Speter	argbuf[i] = 0;	/* termination of command args.  */
273518334Speter	commands[n_commands].prog = argbuf[i + 1];
273618334Speter	commands[n_commands].argv = &argbuf[i + 1];
273718334Speter	string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK);
273818334Speter	if (string)
273918334Speter	  commands[n_commands].argv[0] = string;
274018334Speter	n_commands++;
274118334Speter      }
274218334Speter
274318334Speter  argbuf[argbuf_index] = 0;
274418334Speter
274518334Speter  /* If -v, print what we are about to do, and maybe query.  */
274618334Speter
274718334Speter  if (verbose_flag)
274818334Speter    {
274950599Sobrien      /* For help listings, put a blank line between sub-processes.  */
275050599Sobrien      if (print_help_list)
275150599Sobrien	fputc ('\n', stderr);
275290277Sobrien
275318334Speter      /* Print each piped command as a separate line.  */
275490277Sobrien      for (i = 0; i < n_commands; i++)
275518334Speter	{
275690277Sobrien	  const char *const *j;
275718334Speter
275890277Sobrien     	  if (verbose_only_flag)
275990277Sobrien     	    {
276090277Sobrien	      for (j = commands[i].argv; *j; j++)
276190277Sobrien		{
276290277Sobrien		  const char *p;
276390277Sobrien		  fprintf (stderr, " \"");
276490277Sobrien		  for (p = *j; *p; ++p)
276590277Sobrien		    {
276690277Sobrien		      if (*p == '"' || *p == '\\' || *p == '$')
276790277Sobrien			fputc ('\\', stderr);
276890277Sobrien		      fputc (*p, stderr);
276990277Sobrien		    }
277090277Sobrien		  fputc ('"', stderr);
277190277Sobrien		}
277290277Sobrien     	    }
277390277Sobrien     	  else
277490277Sobrien	    for (j = commands[i].argv; *j; j++)
277590277Sobrien	      fprintf (stderr, " %s", *j);
277618334Speter
277718334Speter	  /* Print a pipe symbol after all but the last command.  */
277818334Speter	  if (i + 1 != n_commands)
277918334Speter	    fprintf (stderr, " |");
278018334Speter	  fprintf (stderr, "\n");
278118334Speter	}
278218334Speter      fflush (stderr);
278390277Sobrien      if (verbose_only_flag != 0)
278490277Sobrien        return 0;
278518334Speter#ifdef DEBUG
278652520Sobrien      notice ("\nGo ahead? (y or n) ");
278718334Speter      fflush (stderr);
278818334Speter      i = getchar ();
278918334Speter      if (i != '\n')
279050599Sobrien	while (getchar () != '\n')
279150599Sobrien	  ;
279250599Sobrien
279318334Speter      if (i != 'y' && i != 'Y')
279418334Speter	return 0;
279518334Speter#endif /* DEBUG */
279618334Speter    }
279718334Speter
279818334Speter  /* Run each piped subprocess.  */
279918334Speter
280018334Speter  for (i = 0; i < n_commands; i++)
280118334Speter    {
280250599Sobrien      char *errmsg_fmt, *errmsg_arg;
280390277Sobrien      const char *string = commands[i].argv[0];
280418334Speter
280590277Sobrien      /* For some bizarre reason, the second argument of execvp() is
280690277Sobrien	 char *const *, not const char *const *.  */
280790277Sobrien      commands[i].pid = pexecute (string, (char *const *) commands[i].argv,
280850599Sobrien				  programname, temp_filename,
280950599Sobrien				  &errmsg_fmt, &errmsg_arg,
281050599Sobrien				  ((i == 0 ? PEXECUTE_FIRST : 0)
281150599Sobrien				   | (i + 1 == n_commands ? PEXECUTE_LAST : 0)
281250599Sobrien				   | (string == commands[i].prog
281350599Sobrien				      ? PEXECUTE_SEARCH : 0)
281450599Sobrien				   | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
281518334Speter
281650599Sobrien      if (commands[i].pid == -1)
281750599Sobrien	pfatal_pexecute (errmsg_fmt, errmsg_arg);
281850599Sobrien
281918334Speter      if (string != commands[i].prog)
282090277Sobrien	free ((PTR) string);
282118334Speter    }
282218334Speter
282318334Speter  execution_count++;
282418334Speter
282518334Speter  /* Wait for all the subprocesses to finish.
282618334Speter     We don't care what order they finish in;
282718334Speter     we know that N_COMMANDS waits will get them all.
282818334Speter     Ignore subprocesses that we don't know about,
282918334Speter     since they can be spawned by the process that exec'ed us.  */
283018334Speter
283118334Speter  {
283218334Speter    int ret_code = 0;
283390277Sobrien#ifdef HAVE_GETRUSAGE
283490277Sobrien    struct timeval d;
283590277Sobrien    double ut = 0.0, st = 0.0;
283690277Sobrien#endif
283718334Speter
283890277Sobrien    for (i = 0; i < n_commands;)
283918334Speter      {
284018334Speter	int j;
284118334Speter	int status;
284218334Speter	int pid;
284318334Speter
284450599Sobrien	pid = pwait (commands[i].pid, &status, 0);
284518334Speter	if (pid < 0)
284618334Speter	  abort ();
284718334Speter
284890277Sobrien#ifdef HAVE_GETRUSAGE
284990277Sobrien	if (report_times)
285090277Sobrien	  {
285190277Sobrien	    /* getrusage returns the total resource usage of all children
285290277Sobrien	       up to now.  Copy the previous values into prus, get the
285390277Sobrien	       current statistics, then take the difference.  */
285490277Sobrien
285590277Sobrien	    prus = rus;
285690277Sobrien	    getrusage (RUSAGE_CHILDREN, &rus);
285790277Sobrien	    d.tv_sec = rus.ru_utime.tv_sec - prus.ru_utime.tv_sec;
285890277Sobrien	    d.tv_usec = rus.ru_utime.tv_usec - prus.ru_utime.tv_usec;
285990277Sobrien	    ut = (double) d.tv_sec + (double) d.tv_usec / 1.0e6;
286090277Sobrien
286190277Sobrien	    d.tv_sec = rus.ru_stime.tv_sec - prus.ru_stime.tv_sec;
286290277Sobrien	    d.tv_usec = rus.ru_stime.tv_usec - prus.ru_stime.tv_usec;
286390277Sobrien	    st = (double) d.tv_sec + (double) d.tv_usec / 1.0e6;
286490277Sobrien	  }
286590277Sobrien#endif
286690277Sobrien
286718334Speter	for (j = 0; j < n_commands; j++)
286818334Speter	  if (commands[j].pid == pid)
286918334Speter	    {
287018334Speter	      i++;
287190277Sobrien	      if (WIFSIGNALED (status))
287218334Speter		{
287390277Sobrien#ifdef SIGPIPE
287490277Sobrien		  /* SIGPIPE is a special case.  It happens in -pipe mode
287590277Sobrien		     when the compiler dies before the preprocessor is
287690277Sobrien		     done, or the assembler dies before the compiler is
287790277Sobrien		     done.  There's generally been an error already, and
287890277Sobrien		     this is just fallout.  So don't generate another error
287990277Sobrien		     unless we would otherwise have succeeded.  */
288090277Sobrien		  if (WTERMSIG (status) == SIGPIPE
288190277Sobrien		      && (signal_count || greatest_status >= MIN_FATAL_STATUS))
288290277Sobrien		    ;
288390277Sobrien		  else
288490277Sobrien#endif
288590277Sobrien		    fatal ("\
288690277SobrienInternal error: %s (program %s)\n\
288790277SobrienPlease submit a full bug report.\n\
288890277SobrienSee %s for instructions.",
288990277Sobrien			   strsignal (WTERMSIG (status)), commands[j].prog,
289090277Sobrien			   GCCBUGURL);
289190277Sobrien		  signal_count++;
289290277Sobrien		  ret_code = -1;
289318334Speter		}
289490277Sobrien	      else if (WIFEXITED (status)
289590277Sobrien		       && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
289690277Sobrien		{
289790277Sobrien		  if (WEXITSTATUS (status) > greatest_status)
289890277Sobrien		    greatest_status = WEXITSTATUS (status);
289990277Sobrien		  ret_code = -1;
290090277Sobrien		}
290190277Sobrien#ifdef HAVE_GETRUSAGE
290290277Sobrien	      if (report_times && ut + st != 0)
290390277Sobrien		notice ("# %s %.2f %.2f\n", commands[j].prog, ut, st);
290490277Sobrien#endif
290518334Speter	      break;
290618334Speter	    }
290718334Speter      }
290818334Speter    return ret_code;
290918334Speter  }
291018334Speter}
291118334Speter
291218334Speter/* Find all the switches given to us
291318334Speter   and make a vector describing them.
291418334Speter   The elements of the vector are strings, one per switch given.
291518334Speter   If a switch uses following arguments, then the `part1' field
291618334Speter   is the switch itself and the `args' field
291718334Speter   is a null-terminated vector containing the following arguments.
291890277Sobrien   The `live_cond' field is:
291990277Sobrien   0 when initialized
292090277Sobrien   1 if the switch is true in a conditional spec,
292190277Sobrien   -1 if false (overridden by a later switch)
292290277Sobrien   -2 if this switch should be ignored (used in %{<S})
292352520Sobrien   The `validated' field is nonzero if any spec has looked at this switch;
292418334Speter   if it remains zero at the end of the run, it must be meaningless.  */
292518334Speter
292690277Sobrien#define SWITCH_OK       0
292790277Sobrien#define SWITCH_FALSE   -1
292890277Sobrien#define SWITCH_IGNORE  -2
292990277Sobrien#define SWITCH_LIVE     1
293090277Sobrien
293118334Speterstruct switchstr
293218334Speter{
293352520Sobrien  const char *part1;
293490277Sobrien  const char **args;
293518334Speter  int live_cond;
293690277Sobrien  unsigned char validated;
293790277Sobrien  unsigned char ordering;
293818334Speter};
293918334Speter
294018334Speterstatic struct switchstr *switches;
294118334Speter
294218334Speterstatic int n_switches;
294318334Speter
294418334Speterstruct infile
294518334Speter{
294652520Sobrien  const char *name;
294752520Sobrien  const char *language;
294818334Speter};
294918334Speter
295018334Speter/* Also a vector of input files specified.  */
295118334Speter
295218334Speterstatic struct infile *infiles;
295318334Speter
295490277Sobrienint n_infiles;
295518334Speter
295652520Sobrien/* This counts the number of libraries added by lang_specific_driver, so that
295750599Sobrien   we can tell if there were any user supplied any files or libraries.  */
295850599Sobrien
295950599Sobrienstatic int added_libraries;
296050599Sobrien
296118334Speter/* And a vector of corresponding output files is made up later.  */
296218334Speter
296390277Sobrienconst char **outfiles;
296418334Speter
296550599Sobrien/* Used to track if none of the -B paths are used.  */
296650599Sobrienstatic int warn_B;
296750599Sobrien
296850599Sobrien/* Used to track if standard path isn't used and -b or -V is specified.  */
296950599Sobrienstatic int warn_std;
297050599Sobrien
297150599Sobrien/* Gives value to pass as "warn" to add_prefix for standard prefixes.  */
297250599Sobrienstatic int *warn_std_ptr = 0;
297350599Sobrien
297490277Sobrien
297553878Sobrien#if defined(FREEBSD_NATIVE)
297653878Sobrien#include <objformat.h>
297753878Sobrien
297853878Sobrientypedef enum { OBJFMT_UNKNOWN, OBJFMT_AOUT, OBJFMT_ELF } objf_t;
297953878Sobrien
298053878Sobrienstatic objf_t objformat = OBJFMT_UNKNOWN;
298150599Sobrien#endif
298290277Sobrien
298390277Sobrien
298450599Sobrien
298590277Sobrien#if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
298650599Sobrien
298750599Sobrien/* Convert NAME to a new name if it is the standard suffix.  DO_EXE
298890277Sobrien   is true if we should look for an executable suffix.  DO_OBJ
298990277Sobrien   is true if we should look for an object suffix.  */
299050599Sobrien
299190277Sobrienstatic const char *
299290277Sobrienconvert_filename (name, do_exe, do_obj)
299390277Sobrien     const char *name;
299490277Sobrien     int do_exe ATTRIBUTE_UNUSED;
299590277Sobrien     int do_obj ATTRIBUTE_UNUSED;
299650599Sobrien{
299790277Sobrien#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
299850599Sobrien  int i;
299990277Sobrien#endif
300052520Sobrien  int len;
300150599Sobrien
300252520Sobrien  if (name == NULL)
300352520Sobrien    return NULL;
300490277Sobrien
300552520Sobrien  len = strlen (name);
300652520Sobrien
300790277Sobrien#ifdef HAVE_TARGET_OBJECT_SUFFIX
300890277Sobrien  /* Convert x.o to x.obj if TARGET_OBJECT_SUFFIX is ".obj".  */
300990277Sobrien  if (do_obj && len > 2
301050599Sobrien      && name[len - 2] == '.'
301150599Sobrien      && name[len - 1] == 'o')
301250599Sobrien    {
301350599Sobrien      obstack_grow (&obstack, name, len - 2);
301490277Sobrien      obstack_grow0 (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
301550599Sobrien      name = obstack_finish (&obstack);
301650599Sobrien    }
301750599Sobrien#endif
301850599Sobrien
301990277Sobrien#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
302050599Sobrien  /* If there is no filetype, make it the executable suffix (which includes
302150599Sobrien     the ".").  But don't get confused if we have just "-o".  */
302290277Sobrien  if (! do_exe || TARGET_EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
302350599Sobrien    return name;
302450599Sobrien
302550599Sobrien  for (i = len - 1; i >= 0; i--)
302652520Sobrien    if (IS_DIR_SEPARATOR (name[i]))
302750599Sobrien      break;
302850599Sobrien
302950599Sobrien  for (i++; i < len; i++)
303050599Sobrien    if (name[i] == '.')
303150599Sobrien      return name;
303250599Sobrien
303350599Sobrien  obstack_grow (&obstack, name, len);
303490277Sobrien  obstack_grow0 (&obstack, TARGET_EXECUTABLE_SUFFIX,
303590277Sobrien		 strlen (TARGET_EXECUTABLE_SUFFIX));
303650599Sobrien  name = obstack_finish (&obstack);
303750599Sobrien#endif
303850599Sobrien
303950599Sobrien  return name;
304050599Sobrien}
304150599Sobrien#endif
304250599Sobrien
304350599Sobrien/* Display the command line switches accepted by gcc.  */
304450599Sobrienstatic void
304550599Sobriendisplay_help ()
304650599Sobrien{
304790277Sobrien  printf (_("Usage: %s [options] file...\n"), programname);
304890277Sobrien  fputs (_("Options:\n"), stdout);
304950599Sobrien
305090277Sobrien  fputs (_("  -pass-exit-codes         Exit with highest error code from a phase\n"), stdout);
305190277Sobrien  fputs (_("  --help                   Display this information\n"), stdout);
305290277Sobrien  fputs (_("  --target-help            Display target specific command line options\n"), stdout);
305350599Sobrien  if (! verbose_flag)
305490277Sobrien    fputs (_("  (Use '-v --help' to display command line options of sub-processes)\n"), stdout);
305590277Sobrien  fputs (_("  -dumpspecs               Display all of the built in spec strings\n"), stdout);
305690277Sobrien  fputs (_("  -dumpversion             Display the version of the compiler\n"), stdout);
305790277Sobrien  fputs (_("  -dumpmachine             Display the compiler's target processor\n"), stdout);
305890277Sobrien  fputs (_("  -print-search-dirs       Display the directories in the compiler's search path\n"), stdout);
305990277Sobrien  fputs (_("  -print-libgcc-file-name  Display the name of the compiler's companion library\n"), stdout);
306090277Sobrien  fputs (_("  -print-file-name=<lib>   Display the full path to library <lib>\n"), stdout);
306190277Sobrien  fputs (_("  -print-prog-name=<prog>  Display the full path to compiler component <prog>\n"), stdout);
306290277Sobrien  fputs (_("  -print-multi-directory   Display the root directory for versions of libgcc\n"), stdout);
306390277Sobrien  fputs (_("\
306490277Sobrien  -print-multi-lib         Display the mapping between command line options and\n\
306590277Sobrien                           multiple library search directories\n"), stdout);
306690277Sobrien  fputs (_("  -Wa,<options>            Pass comma-separated <options> on to the assembler\n"), stdout);
306790277Sobrien  fputs (_("  -Wp,<options>            Pass comma-separated <options> on to the preprocessor\n"), stdout);
306890277Sobrien  fputs (_("  -Wl,<options>            Pass comma-separated <options> on to the linker\n"), stdout);
306990277Sobrien  fputs (_("  -Xlinker <arg>           Pass <arg> on to the linker\n"), stdout);
307090277Sobrien  fputs (_("  -save-temps              Do not delete intermediate files\n"), stdout);
307190277Sobrien  fputs (_("  -pipe                    Use pipes rather than intermediate files\n"), stdout);
307290277Sobrien  fputs (_("  -time                    Time the execution of each subprocess\n"), stdout);
307390277Sobrien  fputs (_("  -specs=<file>            Override built-in specs with the contents of <file>\n"), stdout);
307490277Sobrien  fputs (_("  -std=<standard>          Assume that the input sources are for <standard>\n"), stdout);
307590277Sobrien  fputs (_("  -B <directory>           Add <directory> to the compiler's search paths\n"), stdout);
307690277Sobrien  fputs (_("  -b <machine>             Run gcc for target <machine>, if installed\n"), stdout);
307790277Sobrien  fputs (_("  -V <version>             Run gcc version number <version>, if installed\n"), stdout);
307890277Sobrien  fputs (_("  -v                       Display the programs invoked by the compiler\n"), stdout);
307990277Sobrien  fputs (_("  -###                     Like -v but options quoted and commands not executed\n"), stdout);
308090277Sobrien  fputs (_("  -E                       Preprocess only; do not compile, assemble or link\n"), stdout);
308190277Sobrien  fputs (_("  -S                       Compile only; do not assemble or link\n"), stdout);
308290277Sobrien  fputs (_("  -c                       Compile and assemble, but do not link\n"), stdout);
308390277Sobrien  fputs (_("  -o <file>                Place the output into <file>\n"), stdout);
308490277Sobrien  fputs (_("\
308590277Sobrien  -x <language>            Specify the language of the following input files\n\
308690277Sobrien                           Permissable languages include: c c++ assembler none\n\
308790277Sobrien                           'none' means revert to the default behavior of\n\
308890277Sobrien                           guessing the language based on the file's extension\n\
308990277Sobrien"), stdout);
309050599Sobrien
309190277Sobrien  printf (_("\
309290277Sobrien\nOptions starting with -g, -f, -m, -O, -W, or --param are automatically\n\
309390277Sobrien passed on to the various sub-processes invoked by %s.  In order to pass\n\
309490277Sobrien other options on to these processes the -W<letter> options must be used.\n\
309590277Sobrien"), programname);
309650599Sobrien
309750599Sobrien  /* The rest of the options are displayed by invocations of the various
309850599Sobrien     sub-processes.  */
309950599Sobrien}
310050599Sobrien
310190277Sobrienstatic void
310290277Sobrienadd_preprocessor_option (option, len)
310390277Sobrien     const char *option;
310452520Sobrien     int len;
310590277Sobrien{
310652520Sobrien  n_preprocessor_options++;
310790277Sobrien
310852520Sobrien  if (! preprocessor_options)
310952520Sobrien    preprocessor_options
311052520Sobrien      = (char **) xmalloc (n_preprocessor_options * sizeof (char *));
311152520Sobrien  else
311252520Sobrien    preprocessor_options
311352520Sobrien      = (char **) xrealloc (preprocessor_options,
311452520Sobrien			    n_preprocessor_options * sizeof (char *));
311590277Sobrien
311652520Sobrien  preprocessor_options [n_preprocessor_options - 1] =
311752520Sobrien    save_string (option, len);
311850599Sobrien}
311990277Sobrien
312090277Sobrienstatic void
312190277Sobrienadd_assembler_option (option, len)
312290277Sobrien     const char *option;
312352520Sobrien     int len;
312452520Sobrien{
312552520Sobrien  n_assembler_options++;
312652520Sobrien
312752520Sobrien  if (! assembler_options)
312852520Sobrien    assembler_options
312952520Sobrien      = (char **) xmalloc (n_assembler_options * sizeof (char *));
313052520Sobrien  else
313152520Sobrien    assembler_options
313252520Sobrien      = (char **) xrealloc (assembler_options,
313352520Sobrien			    n_assembler_options * sizeof (char *));
313452520Sobrien
313552520Sobrien  assembler_options [n_assembler_options - 1] = save_string (option, len);
313650599Sobrien}
313790277Sobrien
313890277Sobrienstatic void
313990277Sobrienadd_linker_option (option, len)
314090277Sobrien     const char *option;
314190277Sobrien     int len;
314252520Sobrien{
314352520Sobrien  n_linker_options++;
314452520Sobrien
314552520Sobrien  if (! linker_options)
314652520Sobrien    linker_options
314752520Sobrien      = (char **) xmalloc (n_linker_options * sizeof (char *));
314852520Sobrien  else
314952520Sobrien    linker_options
315052520Sobrien      = (char **) xrealloc (linker_options,
315152520Sobrien			    n_linker_options * sizeof (char *));
315252520Sobrien
315352520Sobrien  linker_options [n_linker_options - 1] = save_string (option, len);
315450599Sobrien}
315550599Sobrien
315618334Speter/* Create the vector `switches' and its contents.
315718334Speter   Store its length in `n_switches'.  */
315818334Speter
315918334Speterstatic void
316018334Speterprocess_command (argc, argv)
316118334Speter     int argc;
316290277Sobrien     const char *const *argv;
316318334Speter{
316490277Sobrien  int i;
316552520Sobrien  const char *temp;
316652520Sobrien  char *temp1;
316790277Sobrien  const char *spec_lang = 0;
316818334Speter  int last_language_n_infiles;
316950599Sobrien  int have_c = 0;
317050599Sobrien  int have_o = 0;
317150599Sobrien  int lang_n_infiles = 0;
317290277Sobrien#ifdef MODIFY_TARGET_NAME
317390277Sobrien  int is_modify_target_name;
317490277Sobrien  int j;
317590277Sobrien#endif
317618334Speter
317752520Sobrien  GET_ENV_PATH_LIST (gcc_exec_prefix, "GCC_EXEC_PREFIX");
317818334Speter
317918334Speter  n_switches = 0;
318018334Speter  n_infiles = 0;
318150599Sobrien  added_libraries = 0;
318218334Speter
318318334Speter  /* Figure compiler version from version string.  */
318418334Speter
318590277Sobrien  compiler_version = temp1 = xstrdup (version_string);
318690277Sobrien
318752520Sobrien  for (; *temp1; ++temp1)
318818334Speter    {
318952520Sobrien      if (*temp1 == ' ')
319018334Speter	{
319152520Sobrien	  *temp1 = '\0';
319218334Speter	  break;
319318334Speter	}
319418334Speter    }
319518334Speter
319690277Sobrien  /* Set up the default search paths.  If there is no GCC_EXEC_PREFIX,
319790277Sobrien     see if we can create it from the pathname specified in argv[0].  */
319818334Speter
319990277Sobrien#ifndef VMS
320090277Sobrien  /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
320190277Sobrien  if (!gcc_exec_prefix)
320290277Sobrien    {
320390277Sobrien      gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix,
320490277Sobrien					      standard_exec_prefix);
320590277Sobrien      if (gcc_exec_prefix)
320690277Sobrien	putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
320790277Sobrien    }
320890277Sobrien#endif
320990277Sobrien
321018334Speter  if (gcc_exec_prefix)
321118334Speter    {
321250599Sobrien      int len = strlen (gcc_exec_prefix);
321390277Sobrien
321490277Sobrien      if (len > (int) sizeof ("/lib/gcc-lib/") - 1
321552520Sobrien	  && (IS_DIR_SEPARATOR (gcc_exec_prefix[len-1])))
321650599Sobrien	{
321750599Sobrien	  temp = gcc_exec_prefix + len - sizeof ("/lib/gcc-lib/") + 1;
321852520Sobrien	  if (IS_DIR_SEPARATOR (*temp)
321990277Sobrien	      && strncmp (temp + 1, "lib", 3) == 0
322052520Sobrien	      && IS_DIR_SEPARATOR (temp[4])
322190277Sobrien	      && strncmp (temp + 5, "gcc-lib", 7) == 0)
322250599Sobrien	    len -= sizeof ("/lib/gcc-lib/") - 1;
322350599Sobrien	}
322450599Sobrien
322550599Sobrien      set_std_prefix (gcc_exec_prefix, len);
322690277Sobrien      add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC",
322790277Sobrien		  PREFIX_PRIORITY_LAST, 0, NULL);
322890277Sobrien      add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC",
322990277Sobrien		  PREFIX_PRIORITY_LAST, 0, NULL);
323018334Speter    }
323118334Speter
323218334Speter  /* COMPILER_PATH and LIBRARY_PATH have values
323318334Speter     that are lists of directory names with colons.  */
323418334Speter
323552520Sobrien  GET_ENV_PATH_LIST (temp, "COMPILER_PATH");
323618334Speter  if (temp)
323718334Speter    {
323852520Sobrien      const char *startp, *endp;
323918334Speter      char *nstore = (char *) alloca (strlen (temp) + 3);
324018334Speter
324118334Speter      startp = endp = temp;
324218334Speter      while (1)
324318334Speter	{
324418334Speter	  if (*endp == PATH_SEPARATOR || *endp == 0)
324518334Speter	    {
324690277Sobrien	      strncpy (nstore, startp, endp - startp);
324718334Speter	      if (endp == startp)
324890277Sobrien		strcpy (nstore, concat (".", dir_separator_str, NULL));
324952520Sobrien	      else if (!IS_DIR_SEPARATOR (endp[-1]))
325018334Speter		{
325190277Sobrien		  nstore[endp - startp] = DIR_SEPARATOR;
325290277Sobrien		  nstore[endp - startp + 1] = 0;
325318334Speter		}
325418334Speter	      else
325590277Sobrien		nstore[endp - startp] = 0;
325690277Sobrien	      add_prefix (&exec_prefixes, nstore, 0,
325790277Sobrien			  PREFIX_PRIORITY_LAST, 0, NULL);
325850599Sobrien	      add_prefix (&include_prefixes,
325990277Sobrien			  concat (nstore, "include", NULL),
326090277Sobrien			  0, PREFIX_PRIORITY_LAST, 0, NULL);
326118334Speter	      if (*endp == 0)
326218334Speter		break;
326318334Speter	      endp = startp = endp + 1;
326418334Speter	    }
326518334Speter	  else
326618334Speter	    endp++;
326718334Speter	}
326818334Speter    }
326918334Speter
327090277Sobrien  GET_ENV_PATH_LIST (temp, LIBRARY_PATH_ENV);
327155220Sobrien  if (temp)
327218334Speter    {
327352520Sobrien      const char *startp, *endp;
327418334Speter      char *nstore = (char *) alloca (strlen (temp) + 3);
327518334Speter
327618334Speter      startp = endp = temp;
327718334Speter      while (1)
327818334Speter	{
327918334Speter	  if (*endp == PATH_SEPARATOR || *endp == 0)
328018334Speter	    {
328190277Sobrien	      strncpy (nstore, startp, endp - startp);
328218334Speter	      if (endp == startp)
328390277Sobrien		strcpy (nstore, concat (".", dir_separator_str, NULL));
328452520Sobrien	      else if (!IS_DIR_SEPARATOR (endp[-1]))
328518334Speter		{
328690277Sobrien		  nstore[endp - startp] = DIR_SEPARATOR;
328790277Sobrien		  nstore[endp - startp + 1] = 0;
328818334Speter		}
328918334Speter	      else
329090277Sobrien		nstore[endp - startp] = 0;
329190277Sobrien	      add_prefix (&startfile_prefixes, nstore, NULL,
329290277Sobrien			  PREFIX_PRIORITY_LAST, 0, NULL);
329318334Speter	      if (*endp == 0)
329418334Speter		break;
329518334Speter	      endp = startp = endp + 1;
329618334Speter	    }
329718334Speter	  else
329818334Speter	    endp++;
329918334Speter	}
330018334Speter    }
330118334Speter
330218334Speter  /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
330352520Sobrien  GET_ENV_PATH_LIST (temp, "LPATH");
330450599Sobrien  if (temp && *cross_compile == '0')
330518334Speter    {
330652520Sobrien      const char *startp, *endp;
330718334Speter      char *nstore = (char *) alloca (strlen (temp) + 3);
330818334Speter
330918334Speter      startp = endp = temp;
331018334Speter      while (1)
331118334Speter	{
331218334Speter	  if (*endp == PATH_SEPARATOR || *endp == 0)
331318334Speter	    {
331490277Sobrien	      strncpy (nstore, startp, endp - startp);
331518334Speter	      if (endp == startp)
331690277Sobrien		strcpy (nstore, concat (".", dir_separator_str, NULL));
331752520Sobrien	      else if (!IS_DIR_SEPARATOR (endp[-1]))
331818334Speter		{
331990277Sobrien		  nstore[endp - startp] = DIR_SEPARATOR;
332090277Sobrien		  nstore[endp - startp + 1] = 0;
332118334Speter		}
332218334Speter	      else
332390277Sobrien		nstore[endp - startp] = 0;
332490277Sobrien	      add_prefix (&startfile_prefixes, nstore, NULL,
332590277Sobrien			  PREFIX_PRIORITY_LAST, 0, NULL);
332618334Speter	      if (*endp == 0)
332718334Speter		break;
332818334Speter	      endp = startp = endp + 1;
332918334Speter	    }
333018334Speter	  else
333118334Speter	    endp++;
333218334Speter	}
333318334Speter    }
333418334Speter
333553878Sobrien#if defined(FREEBSD_NATIVE)
333634229Speter  {
333753878Sobrien    char buf[64];
333853878Sobrien    if (getobjformat (buf, sizeof buf, &argc, argv))
333953878Sobrien      if (strcmp (buf, "aout") == 0)
334053878Sobrien        objformat = OBJFMT_AOUT;
334153878Sobrien      else if (strcmp (buf, "elf") == 0)
334253878Sobrien        objformat = OBJFMT_ELF;
334334229Speter      else
334453878Sobrien        fprintf(stderr, "Unrecognized object format: %s\n", buf);
334534229Speter  }
334634229Speter#endif
334750599Sobrien
334877389Sobrien  /* Options specified as if they appeared on the command line.  */
334977389Sobrien  temp = getenv ("GCC_OPTIONS");
335077389Sobrien  if ((temp) && (strlen (temp) > 0))
335177389Sobrien    {
335277389Sobrien      int len;
335377389Sobrien      int optc = 1;
335477389Sobrien      int new_argc;
335577389Sobrien      char **new_argv;
335677389Sobrien      char *envopts;
335777389Sobrien
335877389Sobrien      while (isspace (*temp))
335977389Sobrien	temp++;
336077389Sobrien      len = strlen (temp);
336177389Sobrien      envopts = (char *) xmalloc (len + 1);
336277389Sobrien      strcpy (envopts, temp);
336377389Sobrien
336477389Sobrien      for (i = 0; i < (len - 1); i++)
336577389Sobrien	if ((isspace (envopts[i])) && ! (isspace (envopts[i+1])))
336677389Sobrien	  optc++;
336777389Sobrien
336877389Sobrien      new_argv = (char **) alloca ((optc + argc) * sizeof(char *));
336977389Sobrien
337077389Sobrien      for (i = 0, new_argc = 1; new_argc <= optc; new_argc++)
337177389Sobrien	{
337277389Sobrien	  while (isspace (envopts[i]))
337377389Sobrien	    i++;
337477389Sobrien	  new_argv[new_argc] = envopts + i;
337577389Sobrien	  while (!isspace (envopts[i]) && (envopts[i] != '\0'))
337677389Sobrien	    i++;
337777389Sobrien	  envopts[i++] = '\0';
337877389Sobrien	}
337977389Sobrien      for (i = 1; i < argc; i++)
338077389Sobrien	new_argv[new_argc++] = argv[i];
338177389Sobrien
338277389Sobrien      argv = new_argv;
338377389Sobrien      argc = new_argc;
338477389Sobrien    }
338577389Sobrien
338618334Speter  /* Convert new-style -- options to old-style.  */
338718334Speter  translate_options (&argc, &argv);
338818334Speter
338950599Sobrien  /* Do language-specific adjustment/addition of flags.  */
339090277Sobrien  lang_specific_driver (&argc, &argv, &added_libraries);
339150599Sobrien
339218334Speter  /* Scan argv twice.  Here, the first time, just count how many switches
339318334Speter     there will be in their vector, and how many input files in theirs.
339490277Sobrien     Also parse any switches that determine the configuration name, such as -b.
339518334Speter     Here we also parse the switches that cc itself uses (e.g. -v).  */
339618334Speter
339718334Speter  for (i = 1; i < argc; i++)
339818334Speter    {
339918334Speter      if (! strcmp (argv[i], "-dumpspecs"))
340018334Speter	{
340150599Sobrien	  struct spec_list *sl;
340250599Sobrien	  init_spec ();
340350599Sobrien	  for (sl = specs; sl; sl = sl->next)
340450599Sobrien	    printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
340590277Sobrien	  if (link_command_spec)
340690277Sobrien	    printf ("*link_command:\n%s\n\n", link_command_spec);
340718334Speter	  exit (0);
340818334Speter	}
340918334Speter      else if (! strcmp (argv[i], "-dumpversion"))
341018334Speter	{
341150599Sobrien	  printf ("%s\n", spec_version);
341218334Speter	  exit (0);
341318334Speter	}
341418334Speter      else if (! strcmp (argv[i], "-dumpmachine"))
341518334Speter	{
341618334Speter	  printf ("%s\n", spec_machine);
341790277Sobrien	  exit (0);
341818334Speter	}
341990277Sobrien      else if (strcmp (argv[i], "-fversion") == 0)
342090277Sobrien	{
342190277Sobrien	  /* translate_options () has turned --version into -fversion.  */
342290277Sobrien	  printf (_("%s (GCC) %s\n"), programname, version_string);
342390277Sobrien	  fputs (_("Copyright (C) 2002 Free Software Foundation, Inc.\n"),
342490277Sobrien		 stdout);
342590277Sobrien	  fputs (_("This is free software; see the source for copying conditions.  There is NO\n\
342690277Sobrienwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
342790277Sobrien		 stdout);
342890277Sobrien	  exit (0);
342990277Sobrien	}
343050599Sobrien      else if (strcmp (argv[i], "-fhelp") == 0)
343150599Sobrien	{
343250599Sobrien	  /* translate_options () has turned --help into -fhelp.  */
343350599Sobrien	  print_help_list = 1;
343450599Sobrien
343550599Sobrien	  /* We will be passing a dummy file on to the sub-processes.  */
343650599Sobrien	  n_infiles++;
343750599Sobrien	  n_switches++;
343890277Sobrien
343990277Sobrien	  /* CPP driver cannot obtain switch from cc1_options.  */
344090277Sobrien	  if (is_cpp_driver)
344190277Sobrien	    add_preprocessor_option ("--help", 6);
344250599Sobrien	  add_assembler_option ("--help", 6);
344350599Sobrien	  add_linker_option ("--help", 6);
344450599Sobrien	}
344590277Sobrien      else if (strcmp (argv[i], "-ftarget-help") == 0)
344690277Sobrien        {
344790277Sobrien          /* translate_options() has turned --target-help into -ftarget-help.  */
344890277Sobrien          target_help_flag = 1;
344990277Sobrien
345090277Sobrien          /* We will be passing a dummy file on to the sub-processes.  */
345190277Sobrien          n_infiles++;
345290277Sobrien          n_switches++;
345390277Sobrien
345490277Sobrien	  /* CPP driver cannot obtain switch from cc1_options.  */
345590277Sobrien	  if (is_cpp_driver)
345690277Sobrien	    add_preprocessor_option ("--target-help", 13);
345790277Sobrien          add_assembler_option ("--target-help", 13);
345890277Sobrien          add_linker_option ("--target-help", 13);
345990277Sobrien        }
346090277Sobrien      else if (! strcmp (argv[i], "-pass-exit-codes"))
346190277Sobrien	{
346290277Sobrien	  pass_exit_codes = 1;
346390277Sobrien	  n_switches++;
346490277Sobrien	}
346518334Speter      else if (! strcmp (argv[i], "-print-search-dirs"))
346618334Speter	print_search_dirs = 1;
346718334Speter      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
346818334Speter	print_file_name = "libgcc.a";
346918334Speter      else if (! strncmp (argv[i], "-print-file-name=", 17))
347018334Speter	print_file_name = argv[i] + 17;
347118334Speter      else if (! strncmp (argv[i], "-print-prog-name=", 17))
347218334Speter	print_prog_name = argv[i] + 17;
347318334Speter      else if (! strcmp (argv[i], "-print-multi-lib"))
347418334Speter	print_multi_lib = 1;
347518334Speter      else if (! strcmp (argv[i], "-print-multi-directory"))
347618334Speter	print_multi_directory = 1;
347718334Speter      else if (! strncmp (argv[i], "-Wa,", 4))
347818334Speter	{
347918334Speter	  int prev, j;
348018334Speter	  /* Pass the rest of this option to the assembler.  */
348118334Speter
348218334Speter	  /* Split the argument at commas.  */
348318334Speter	  prev = 4;
348418334Speter	  for (j = 4; argv[i][j]; j++)
348518334Speter	    if (argv[i][j] == ',')
348618334Speter	      {
348750599Sobrien		add_assembler_option (argv[i] + prev, j - prev);
348818334Speter		prev = j + 1;
348918334Speter	      }
349090277Sobrien
349118334Speter	  /* Record the part after the last comma.  */
349250599Sobrien	  add_assembler_option (argv[i] + prev, j - prev);
349318334Speter	}
349418334Speter      else if (! strncmp (argv[i], "-Wp,", 4))
349518334Speter	{
349618334Speter	  int prev, j;
349718334Speter	  /* Pass the rest of this option to the preprocessor.  */
349818334Speter
349918334Speter	  /* Split the argument at commas.  */
350018334Speter	  prev = 4;
350118334Speter	  for (j = 4; argv[i][j]; j++)
350218334Speter	    if (argv[i][j] == ',')
350318334Speter	      {
350450599Sobrien		add_preprocessor_option (argv[i] + prev, j - prev);
350518334Speter		prev = j + 1;
350618334Speter	      }
350790277Sobrien
350818334Speter	  /* Record the part after the last comma.  */
350950599Sobrien	  add_preprocessor_option (argv[i] + prev, j - prev);
351018334Speter	}
351118334Speter      else if (argv[i][0] == '+' && argv[i][1] == 'e')
351218334Speter	/* The +e options to the C++ front-end.  */
351318334Speter	n_switches++;
351418334Speter      else if (strncmp (argv[i], "-Wl,", 4) == 0)
351518334Speter	{
351618334Speter	  int j;
351718334Speter	  /* Split the argument at commas.  */
351818334Speter	  for (j = 3; argv[i][j]; j++)
351918334Speter	    n_infiles += (argv[i][j] == ',');
352018334Speter	}
352118334Speter      else if (strcmp (argv[i], "-Xlinker") == 0)
352218334Speter	{
352318334Speter	  if (i + 1 == argc)
352418334Speter	    fatal ("argument to `-Xlinker' is missing");
352518334Speter
352618334Speter	  n_infiles++;
352718334Speter	  i++;
352818334Speter	}
352977389Sobrien      else if (strcmp (argv[i], "-l") == 0)
353077389Sobrien	{
353177389Sobrien	  if (i + 1 == argc)
353277389Sobrien	    fatal ("argument to `-l' is missing");
353377389Sobrien
353477389Sobrien	  n_infiles++;
353577389Sobrien	  i++;
353677389Sobrien	}
353718334Speter      else if (strncmp (argv[i], "-l", 2) == 0)
353818334Speter	n_infiles++;
353950599Sobrien      else if (strcmp (argv[i], "-save-temps") == 0)
354050599Sobrien	{
354150599Sobrien	  save_temps_flag = 1;
354250599Sobrien	  n_switches++;
354350599Sobrien	}
354450599Sobrien      else if (strcmp (argv[i], "-specs") == 0)
354550599Sobrien	{
354650599Sobrien	  struct user_specs *user = (struct user_specs *)
354750599Sobrien	    xmalloc (sizeof (struct user_specs));
354850599Sobrien	  if (++i >= argc)
354950599Sobrien	    fatal ("argument to `-specs' is missing");
355050599Sobrien
355190277Sobrien	  user->next = (struct user_specs *) 0;
355250599Sobrien	  user->filename = argv[i];
355350599Sobrien	  if (user_specs_tail)
355450599Sobrien	    user_specs_tail->next = user;
355550599Sobrien	  else
355650599Sobrien	    user_specs_head = user;
355750599Sobrien	  user_specs_tail = user;
355850599Sobrien	}
355950599Sobrien      else if (strncmp (argv[i], "-specs=", 7) == 0)
356050599Sobrien	{
356150599Sobrien	  struct user_specs *user = (struct user_specs *)
356250599Sobrien	    xmalloc (sizeof (struct user_specs));
356350599Sobrien	  if (strlen (argv[i]) == 7)
356450599Sobrien	    fatal ("argument to `-specs=' is missing");
356550599Sobrien
356690277Sobrien	  user->next = (struct user_specs *) 0;
356790277Sobrien	  user->filename = argv[i] + 7;
356850599Sobrien	  if (user_specs_tail)
356950599Sobrien	    user_specs_tail->next = user;
357050599Sobrien	  else
357150599Sobrien	    user_specs_head = user;
357250599Sobrien	  user_specs_tail = user;
357350599Sobrien	}
357490277Sobrien      else if (strcmp (argv[i], "-time") == 0)
357590277Sobrien	report_times = 1;
357690277Sobrien      else if (strcmp (argv[i], "-###") == 0)
357790277Sobrien	{
357890277Sobrien	  /* This is similar to -v except that there is no execution
357990277Sobrien	     of the commands and the echoed arguments are quoted.  It
358090277Sobrien	     is intended for use in shell scripts to capture the
358190277Sobrien	     driver-generated command line.  */
358290277Sobrien	  verbose_only_flag++;
358390277Sobrien	  verbose_flag++;
358490277Sobrien	}
358518334Speter      else if (argv[i][0] == '-' && argv[i][1] != 0)
358618334Speter	{
358790277Sobrien	  const char *p = &argv[i][1];
358890277Sobrien	  int c = *p;
358918334Speter
359018334Speter	  switch (c)
359118334Speter	    {
359218334Speter	    case 'b':
359390277Sobrien	      n_switches++;
359418334Speter	      if (p[1] == 0 && i + 1 == argc)
359518334Speter		fatal ("argument to `-b' is missing");
359618334Speter	      if (p[1] == 0)
359718334Speter		spec_machine = argv[++i];
359818334Speter	      else
359918334Speter		spec_machine = p + 1;
360050599Sobrien
360150599Sobrien	      warn_std_ptr = &warn_std;
360218334Speter	      break;
360318334Speter
360418334Speter	    case 'B':
360518334Speter	      {
360690277Sobrien		const char *value;
360790277Sobrien		int len;
360890277Sobrien
360918334Speter		if (p[1] == 0 && i + 1 == argc)
361018334Speter		  fatal ("argument to `-B' is missing");
361118334Speter		if (p[1] == 0)
361218334Speter		  value = argv[++i];
361318334Speter		else
361418334Speter		  value = p + 1;
361518334Speter
361690277Sobrien		len = strlen (value);
361790277Sobrien
361890277Sobrien		/* Catch the case where the user has forgotten to append a
361990277Sobrien		   directory separator to the path.  Note, they may be using
362090277Sobrien		   -B to add an executable name prefix, eg "i386-elf-", in
362190277Sobrien		   order to distinguish between multiple installations of
362290277Sobrien		   GCC in the same directory.  Hence we must check to see
362390277Sobrien		   if appending a directory separator actually makes a
362490277Sobrien		   valid directory name.  */
362590277Sobrien		if (! IS_DIR_SEPARATOR (value [len - 1])
362690277Sobrien		    && is_directory (value, "", 0))
362790277Sobrien		  {
362890277Sobrien		    char *tmp = xmalloc (len + 2);
362990277Sobrien		    strcpy (tmp, value);
363090277Sobrien		    tmp[len] = DIR_SEPARATOR;
363190277Sobrien		    tmp[++ len] = 0;
363290277Sobrien		    value = tmp;
363390277Sobrien		  }
363490277Sobrien
363590277Sobrien		/* As a kludge, if the arg is "[foo/]stageN/", just
363690277Sobrien		   add "[foo/]include" to the include prefix.  */
363790277Sobrien		if ((len == 7
363890277Sobrien		     || (len > 7
363990277Sobrien			 && (IS_DIR_SEPARATOR (value[len - 8]))))
364090277Sobrien		    && strncmp (value + len - 7, "stage", 5) == 0
364190277Sobrien		    && ISDIGIT (value[len - 2])
364290277Sobrien		    && (IS_DIR_SEPARATOR (value[len - 1])))
364390277Sobrien		  {
364490277Sobrien		    if (len == 7)
364590277Sobrien		      add_prefix (&include_prefixes, "include", NULL,
364690277Sobrien				  PREFIX_PRIORITY_B_OPT, 0, NULL);
364790277Sobrien		    else
364890277Sobrien		      {
364990277Sobrien			char * string = xmalloc (len + 1);
365090277Sobrien
365190277Sobrien			strncpy (string, value, len - 7);
365290277Sobrien			strcpy (string + len - 7, "include");
365390277Sobrien			add_prefix (&include_prefixes, string, NULL,
365490277Sobrien				    PREFIX_PRIORITY_B_OPT, 0, NULL);
365590277Sobrien		      }
365690277Sobrien		  }
365790277Sobrien
365890277Sobrien		add_prefix (&exec_prefixes, value, NULL,
365990277Sobrien			    PREFIX_PRIORITY_B_OPT, 0, &warn_B);
366090277Sobrien		add_prefix (&startfile_prefixes, value, NULL,
366190277Sobrien			    PREFIX_PRIORITY_B_OPT, 0, &warn_B);
366290277Sobrien		add_prefix (&include_prefixes, concat (value, "include", NULL),
366390277Sobrien			    NULL, PREFIX_PRIORITY_B_OPT, 0, NULL);
366490277Sobrien		n_switches++;
366518334Speter	      }
366618334Speter	      break;
366718334Speter
366818334Speter	    case 'v':	/* Print our subcommands and print versions.  */
366918334Speter	      n_switches++;
367018334Speter	      /* If they do anything other than exactly `-v', don't set
367118334Speter		 verbose_flag; rather, continue on to give the error.  */
367218334Speter	      if (p[1] != 0)
367318334Speter		break;
367418334Speter	      verbose_flag++;
367518334Speter	      break;
367618334Speter
367718334Speter	    case 'V':
367850599Sobrien	      n_switches++;
367918334Speter	      if (p[1] == 0 && i + 1 == argc)
368018334Speter		fatal ("argument to `-V' is missing");
368118334Speter	      if (p[1] == 0)
368218334Speter		spec_version = argv[++i];
368318334Speter	      else
368418334Speter		spec_version = p + 1;
368518334Speter	      compiler_version = spec_version;
368650599Sobrien	      warn_std_ptr = &warn_std;
368750599Sobrien
368850599Sobrien	      /* Validate the version number.  Use the same checks
368950599Sobrien		 done when inserting it into a spec.
369050599Sobrien
369150599Sobrien		 The format of the version string is
369250599Sobrien		 ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */
369350599Sobrien	      {
369452520Sobrien		const char *v = compiler_version;
369550599Sobrien
369650599Sobrien		/* Ignore leading non-digits.  i.e. "foo-" in "foo-2.7.2".  */
369750599Sobrien		while (! ISDIGIT (*v))
369850599Sobrien		  v++;
369950599Sobrien
370050599Sobrien		if (v > compiler_version && v[-1] != '-')
370150599Sobrien		  fatal ("invalid version number format");
370250599Sobrien
370350599Sobrien		/* Set V after the first period.  */
370450599Sobrien		while (ISDIGIT (*v))
370550599Sobrien		  v++;
370650599Sobrien
370750599Sobrien		if (*v != '.')
370850599Sobrien		  fatal ("invalid version number format");
370950599Sobrien
371050599Sobrien		v++;
371150599Sobrien		while (ISDIGIT (*v))
371250599Sobrien		  v++;
371350599Sobrien
371450599Sobrien		if (*v != 0 && *v != ' ' && *v != '.' && *v != '-')
371550599Sobrien		  fatal ("invalid version number format");
371650599Sobrien	      }
371718334Speter	      break;
371818334Speter
371950599Sobrien	    case 'S':
372050599Sobrien	    case 'c':
372150599Sobrien	      if (p[1] == 0)
372218334Speter		{
372350599Sobrien		  have_c = 1;
372418334Speter		  n_switches++;
372518334Speter		  break;
372618334Speter		}
372750599Sobrien	      goto normal_switch;
372850599Sobrien
372950599Sobrien	    case 'o':
373050599Sobrien	      have_o = 1;
373190277Sobrien#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
373250599Sobrien	      if (! have_c)
373350599Sobrien		{
373450599Sobrien		  int skip;
373590277Sobrien
373650599Sobrien		  /* Forward scan, just in case -S or -c is specified
373750599Sobrien		     after -o.  */
373850599Sobrien		  int j = i + 1;
373950599Sobrien		  if (p[1] == 0)
374050599Sobrien		    ++j;
374150599Sobrien		  while (j < argc)
374250599Sobrien		    {
374350599Sobrien		      if (argv[j][0] == '-')
374450599Sobrien			{
374550599Sobrien			  if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
374650599Sobrien			      && argv[j][2] == 0)
374750599Sobrien			    {
374850599Sobrien			      have_c = 1;
374950599Sobrien			      break;
375050599Sobrien			    }
375190277Sobrien			  else if ((skip = SWITCH_TAKES_ARG (argv[j][1])))
375250599Sobrien			    j += skip - (argv[j][2] != 0);
375390277Sobrien			  else if ((skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1)))
375450599Sobrien			    j += skip;
375550599Sobrien			}
375650599Sobrien		      j++;
375750599Sobrien		    }
375850599Sobrien		}
375950599Sobrien#endif
376090277Sobrien#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
376150599Sobrien	      if (p[1] == 0)
376290277Sobrien		argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
376350599Sobrien	      else
376490277Sobrien		argv[i] = convert_filename (argv[i], ! have_c, 0);
376550599Sobrien#endif
376650599Sobrien	      goto normal_switch;
376750599Sobrien
376818334Speter	    default:
376950599Sobrien	    normal_switch:
377090277Sobrien
377190277Sobrien#ifdef MODIFY_TARGET_NAME
377290277Sobrien	      is_modify_target_name = 0;
377390277Sobrien
377490277Sobrien	      for (j = 0;
377590277Sobrien		   j < sizeof modify_target / sizeof modify_target[0]; j++)
377690277Sobrien		if (! strcmp (argv[i], modify_target[j].sw))
377790277Sobrien		  {
377890277Sobrien		    char *new_name
377990277Sobrien		      = (char *) xmalloc (strlen (modify_target[j].str)
378090277Sobrien					  + strlen (spec_machine));
378190277Sobrien		    const char *p, *r;
378290277Sobrien		    char *q;
378390277Sobrien		    int made_addition = 0;
378490277Sobrien
378590277Sobrien		    is_modify_target_name = 1;
378690277Sobrien		    for (p = spec_machine, q = new_name; *p != 0; )
378790277Sobrien		      {
378890277Sobrien			if (modify_target[j].add_del == DELETE
378990277Sobrien			    && (! strncmp (q, modify_target[j].str,
379090277Sobrien					   strlen (modify_target[j].str))))
379190277Sobrien			  p += strlen (modify_target[j].str);
379290277Sobrien			else if (modify_target[j].add_del == ADD
379390277Sobrien				 && ! made_addition && *p == '-')
379490277Sobrien			  {
379590277Sobrien			    for (r = modify_target[j].str; *r != 0; )
379690277Sobrien			      *q++ = *r++;
379790277Sobrien			    made_addition = 1;
379890277Sobrien			  }
379990277Sobrien
380090277Sobrien			*q++ = *p++;
380190277Sobrien		      }
380290277Sobrien
380390277Sobrien		    spec_machine = new_name;
380490277Sobrien		  }
380590277Sobrien
380690277Sobrien	      if (is_modify_target_name)
380790277Sobrien		break;
380890277Sobrien#endif
380990277Sobrien
381018334Speter	      n_switches++;
381118334Speter
381218334Speter	      if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
381318334Speter		i += SWITCH_TAKES_ARG (c) - (p[1] != 0);
381418334Speter	      else if (WORD_SWITCH_TAKES_ARG (p))
381518334Speter		i += WORD_SWITCH_TAKES_ARG (p);
381618334Speter	    }
381718334Speter	}
381818334Speter      else
381950599Sobrien	{
382050599Sobrien	  n_infiles++;
382150599Sobrien	  lang_n_infiles++;
382250599Sobrien	}
382318334Speter    }
382418334Speter
382550599Sobrien  if (have_c && have_o && lang_n_infiles > 1)
382650599Sobrien    fatal ("cannot specify -o with -c or -S and multiple compilations");
382750599Sobrien
382818334Speter  /* Set up the search paths before we go looking for config files.  */
382918334Speter
383018334Speter  /* These come before the md prefixes so that we will find gcc's subcommands
383118334Speter     (such as cpp) rather than those of the host system.  */
383218334Speter  /* Use 2 as fourth arg meaning try just the machine as a suffix,
383318334Speter     as well as trying the machine and the version.  */
383418346Speter#ifdef FREEBSD_NATIVE
383553878Sobrien  switch (objformat)
383653878Sobrien    {
383753878Sobrien    case OBJFMT_AOUT:
383853878Sobrien      n_switches++;		/* add implied -maout */
383955220Sobrien      add_prefix (&exec_prefixes, PREFIX"/libexec/aout/", "BINUTILS",
384053878Sobrien		  0, 0, NULL_PTR);
384153878Sobrien      break;
384253878Sobrien    case OBJFMT_ELF:
384355220Sobrien      add_prefix (&exec_prefixes, PREFIX"/libexec/elf/", "BINUTILS",
384453878Sobrien		  0, 0, NULL_PTR);
384553878Sobrien      break;
384654778Sobrien    case OBJFMT_UNKNOWN:
384754778Sobrien      fatal ("object format unknown");
384853878Sobrien    }
384918346Speter#else /* not FREEBSD_NATIVE */
385018334Speter#ifndef OS2
385190277Sobrien  add_prefix (&exec_prefixes, standard_exec_prefix, "GCC",
385290277Sobrien	      PREFIX_PRIORITY_LAST, 1, warn_std_ptr);
385350599Sobrien  add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
385490277Sobrien	      PREFIX_PRIORITY_LAST, 2, warn_std_ptr);
385550599Sobrien  add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
385690277Sobrien	      PREFIX_PRIORITY_LAST, 2, warn_std_ptr);
385718334Speter#endif
385818334Speter
385950599Sobrien  add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
386090277Sobrien	      PREFIX_PRIORITY_LAST, 1, warn_std_ptr);
386150599Sobrien  add_prefix (&startfile_prefixes, standard_exec_prefix_1, "BINUTILS",
386290277Sobrien	      PREFIX_PRIORITY_LAST, 1, warn_std_ptr);
386318346Speter#endif /* FREEBSD_NATIVE */
386418334Speter
386590277Sobrien  tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
386690277Sobrien			   dir_separator_str, NULL);
386718334Speter
386818334Speter  /* If tooldir is relative, base it on exec_prefixes.  A relative
386918334Speter     tooldir lets us move the installed tree as a unit.
387018334Speter
387118334Speter     If GCC_EXEC_PREFIX is defined, then we want to add two relative
387218334Speter     directories, so that we can search both the user specified directory
387318334Speter     and the standard place.  */
387418334Speter
387590277Sobrien  if (!IS_ABSOLUTE_PATHNAME (tooldir_prefix))
387618334Speter    {
387718334Speter      if (gcc_exec_prefix)
387818334Speter	{
387918334Speter	  char *gcc_exec_tooldir_prefix
388050599Sobrien	    = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
388190277Sobrien		      spec_version, dir_separator_str, tooldir_prefix, NULL);
388218334Speter
388318334Speter	  add_prefix (&exec_prefixes,
388490277Sobrien		      concat (gcc_exec_tooldir_prefix, "bin",
388590277Sobrien			      dir_separator_str, NULL),
388690277Sobrien		      NULL, PREFIX_PRIORITY_LAST, 0, NULL);
388718334Speter	  add_prefix (&startfile_prefixes,
388890277Sobrien		      concat (gcc_exec_tooldir_prefix, "lib",
388990277Sobrien			      dir_separator_str, NULL),
389090277Sobrien		      NULL, PREFIX_PRIORITY_LAST, 0, NULL);
389118334Speter	}
389218334Speter
389350599Sobrien      tooldir_prefix = concat (standard_exec_prefix, spec_machine,
389490277Sobrien			       dir_separator_str, spec_version,
389590277Sobrien			       dir_separator_str, tooldir_prefix, NULL);
389618334Speter    }
389718334Speter
389818346Speter#ifndef FREEBSD_NATIVE
389990277Sobrien  add_prefix (&exec_prefixes,
390090277Sobrien	      concat (tooldir_prefix, "bin", dir_separator_str, NULL),
390190277Sobrien	      "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL);
390218334Speter  add_prefix (&startfile_prefixes,
390390277Sobrien	      concat (tooldir_prefix, "lib", dir_separator_str, NULL),
390490277Sobrien	      "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL);
390518346Speter#endif /* FREEBSD_NATIVE */
390618334Speter
390718334Speter  /* More prefixes are enabled in main, after we read the specs file
390818334Speter     and determine whether this is cross-compilation or not.  */
390918334Speter
391018334Speter  /* Then create the space for the vectors and scan again.  */
391118334Speter
391218334Speter  switches = ((struct switchstr *)
391318334Speter	      xmalloc ((n_switches + 1) * sizeof (struct switchstr)));
391418334Speter  infiles = (struct infile *) xmalloc ((n_infiles + 1) * sizeof (struct infile));
391518334Speter  n_switches = 0;
391618334Speter  n_infiles = 0;
391718334Speter  last_language_n_infiles = -1;
391818334Speter
391918334Speter  /* This, time, copy the text of each switch and store a pointer
392018334Speter     to the copy in the vector of switches.
392118334Speter     Store all the infiles in their vector.  */
392218334Speter
392353878Sobrien#if defined(FREEBSD_NATIVE)
392453878Sobrien  switch (objformat)
392553878Sobrien    {
392653878Sobrien    case OBJFMT_AOUT:
392753878Sobrien      switches[n_switches].part1 = "maout";
392853878Sobrien      switches[n_switches].args = 0;
392953878Sobrien      switches[n_switches].live_cond = 0;
393053878Sobrien      switches[n_switches].validated = 0;
393153878Sobrien      n_switches++;
393253878Sobrien      putenv("OBJFORMAT=aout");
393353878Sobrien      break;
393453878Sobrien    case OBJFMT_ELF:
393553878Sobrien      putenv("OBJFORMAT=elf");
393653878Sobrien      break;
393754778Sobrien    case OBJFMT_UNKNOWN:
393854778Sobrien      fatal ("object format unknown");
393953878Sobrien    }
394034229Speter#endif
394134229Speter
394218334Speter  for (i = 1; i < argc; i++)
394318334Speter    {
394418334Speter      /* Just skip the switches that were handled by the preceding loop.  */
394590277Sobrien#ifdef MODIFY_TARGET_NAME
394690277Sobrien      is_modify_target_name = 0;
394790277Sobrien
394890277Sobrien      for (j = 0; j < sizeof modify_target / sizeof modify_target[0]; j++)
394990277Sobrien	if (! strcmp (argv[i], modify_target[j].sw))
395090277Sobrien	  is_modify_target_name = 1;
395190277Sobrien
395290277Sobrien      if (is_modify_target_name)
395390277Sobrien	;
395490277Sobrien      else
395590277Sobrien#endif
395618334Speter      if (! strncmp (argv[i], "-Wa,", 4))
395718334Speter	;
395818334Speter      else if (! strncmp (argv[i], "-Wp,", 4))
395918334Speter	;
396090277Sobrien      else if (! strcmp (argv[i], "-pass-exit-codes"))
396190277Sobrien	;
396218334Speter      else if (! strcmp (argv[i], "-print-search-dirs"))
396318334Speter	;
396418334Speter      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
396518334Speter	;
396618334Speter      else if (! strncmp (argv[i], "-print-file-name=", 17))
396718334Speter	;
396818334Speter      else if (! strncmp (argv[i], "-print-prog-name=", 17))
396918334Speter	;
397018334Speter      else if (! strcmp (argv[i], "-print-multi-lib"))
397118334Speter	;
397218334Speter      else if (! strcmp (argv[i], "-print-multi-directory"))
397318334Speter	;
397490277Sobrien      else if (! strcmp (argv[i], "-ftarget-help"))
397590277Sobrien	;
397690277Sobrien      else if (! strcmp (argv[i], "-fhelp"))
397790277Sobrien	;
397818334Speter      else if (argv[i][0] == '+' && argv[i][1] == 'e')
397918334Speter	{
398018334Speter	  /* Compensate for the +e options to the C++ front-end;
398118334Speter	     they're there simply for cfront call-compatibility.  We do
398218334Speter	     some magic in default_compilers to pass them down properly.
398318334Speter	     Note we deliberately start at the `+' here, to avoid passing
398418334Speter	     -e0 or -e1 down into the linker.  */
398518334Speter	  switches[n_switches].part1 = &argv[i][0];
398618334Speter	  switches[n_switches].args = 0;
398790277Sobrien	  switches[n_switches].live_cond = SWITCH_OK;
398852520Sobrien	  switches[n_switches].validated = 0;
398918334Speter	  n_switches++;
399018334Speter	}
399118334Speter      else if (strncmp (argv[i], "-Wl,", 4) == 0)
399218334Speter	{
399318334Speter	  int prev, j;
399418334Speter	  /* Split the argument at commas.  */
399518334Speter	  prev = 4;
399618334Speter	  for (j = 4; argv[i][j]; j++)
399718334Speter	    if (argv[i][j] == ',')
399818334Speter	      {
399950599Sobrien		infiles[n_infiles].language = "*";
400018334Speter		infiles[n_infiles++].name
400118334Speter		  = save_string (argv[i] + prev, j - prev);
400218334Speter		prev = j + 1;
400318334Speter	      }
400418334Speter	  /* Record the part after the last comma.  */
400550599Sobrien	  infiles[n_infiles].language = "*";
400618334Speter	  infiles[n_infiles++].name = argv[i] + prev;
400718334Speter	}
400818334Speter      else if (strcmp (argv[i], "-Xlinker") == 0)
400918334Speter	{
401050599Sobrien	  infiles[n_infiles].language = "*";
401118334Speter	  infiles[n_infiles++].name = argv[++i];
401218334Speter	}
401377389Sobrien      else if (strcmp (argv[i], "-l") == 0)
401477389Sobrien	{ /* POSIX allows separation of -l and the lib arg;
401577389Sobrien	     canonicalize by concatenating -l with its arg */
401677389Sobrien	  infiles[n_infiles].language = "*";
401777389Sobrien	  infiles[n_infiles++].name = concat ("-l", argv[++i], NULL);
401877389Sobrien	}
401918334Speter      else if (strncmp (argv[i], "-l", 2) == 0)
402018334Speter	{
402150599Sobrien	  infiles[n_infiles].language = "*";
402218334Speter	  infiles[n_infiles++].name = argv[i];
402318334Speter	}
402450599Sobrien      else if (strcmp (argv[i], "-specs") == 0)
402550599Sobrien	i++;
402650599Sobrien      else if (strncmp (argv[i], "-specs=", 7) == 0)
402750599Sobrien	;
402890277Sobrien      else if (strcmp (argv[i], "-time") == 0)
402990277Sobrien	;
403090277Sobrien      else if ((save_temps_flag || report_times)
403190277Sobrien	       && strcmp (argv[i], "-pipe") == 0)
403290277Sobrien	{
403390277Sobrien	  /* -save-temps overrides -pipe, so that temp files are produced */
403490277Sobrien	  if (save_temps_flag)
403590277Sobrien	    error ("warning: -pipe ignored because -save-temps specified");
403690277Sobrien          /* -time overrides -pipe because we can't get correct stats when
403790277Sobrien	     multiple children are running at once.  */
403890277Sobrien	  else if (report_times)
403990277Sobrien	    error ("warning: -pipe ignored because -time specified");
404090277Sobrien	}
404190277Sobrien      else if (strcmp (argv[i], "-###") == 0)
404290277Sobrien	;
404318334Speter      else if (argv[i][0] == '-' && argv[i][1] != 0)
404418334Speter	{
404590277Sobrien	  const char *p = &argv[i][1];
404690277Sobrien	  int c = *p;
404718334Speter
404818334Speter	  if (c == 'x')
404918334Speter	    {
405018334Speter	      if (p[1] == 0 && i + 1 == argc)
405118334Speter		fatal ("argument to `-x' is missing");
405218334Speter	      if (p[1] == 0)
405318334Speter		spec_lang = argv[++i];
405418334Speter	      else
405518334Speter		spec_lang = p + 1;
405618334Speter	      if (! strcmp (spec_lang, "none"))
405718334Speter		/* Suppress the warning if -xnone comes after the last input
405818334Speter		   file, because alternate command interfaces like g++ might
405918334Speter		   find it useful to place -xnone after each input file.  */
406018334Speter		spec_lang = 0;
406118334Speter	      else
406218334Speter		last_language_n_infiles = n_infiles;
406318334Speter	      continue;
406418334Speter	    }
406518334Speter	  switches[n_switches].part1 = p;
406618334Speter	  /* Deal with option arguments in separate argv elements.  */
406718334Speter	  if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
406818334Speter	      || WORD_SWITCH_TAKES_ARG (p))
406918334Speter	    {
407018334Speter	      int j = 0;
407118334Speter	      int n_args = WORD_SWITCH_TAKES_ARG (p);
407218334Speter
407318334Speter	      if (n_args == 0)
407418334Speter		{
407518334Speter		  /* Count only the option arguments in separate argv elements.  */
407618334Speter		  n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
407718334Speter		}
407818334Speter	      if (i + n_args >= argc)
407918334Speter		fatal ("argument to `-%s' is missing", p);
408018334Speter	      switches[n_switches].args
408190277Sobrien		= (const char **) xmalloc ((n_args + 1) * sizeof(const char *));
408218334Speter	      while (j < n_args)
408318334Speter		switches[n_switches].args[j++] = argv[++i];
408418334Speter	      /* Null-terminate the vector.  */
408518334Speter	      switches[n_switches].args[j] = 0;
408618334Speter	    }
408790277Sobrien	  else if (strchr (switches_need_spaces, c))
408818334Speter	    {
408950599Sobrien	      /* On some systems, ld cannot handle some options without
409050599Sobrien		 a space.  So split the option from its argument.  */
409150599Sobrien	      char *part1 = (char *) xmalloc (2);
409250599Sobrien	      part1[0] = c;
409350599Sobrien	      part1[1] = '\0';
409490277Sobrien
409550599Sobrien	      switches[n_switches].part1 = part1;
409690277Sobrien	      switches[n_switches].args
409790277Sobrien		= (const char **) xmalloc (2 * sizeof (const char *));
409890277Sobrien	      switches[n_switches].args[0] = xstrdup (p+1);
409918334Speter	      switches[n_switches].args[1] = 0;
410018334Speter	    }
410118334Speter	  else
410218334Speter	    switches[n_switches].args = 0;
410318334Speter
410490277Sobrien	  switches[n_switches].live_cond = SWITCH_OK;
410552520Sobrien	  switches[n_switches].validated = 0;
410690277Sobrien	  switches[n_switches].ordering = 0;
410790277Sobrien	  /* These are always valid, since gcc.c itself understands it.  */
410890277Sobrien	  if (!strcmp (p, "save-temps")
410990277Sobrien	      || !strcmp (p, "static-libgcc")
411090277Sobrien	      || !strcmp (p, "shared-libgcc"))
411152520Sobrien	    switches[n_switches].validated = 1;
411290277Sobrien	  else
411390277Sobrien	    {
411490277Sobrien	      char ch = switches[n_switches].part1[0];
411590277Sobrien	      if (ch == 'V' || ch == 'b' || ch == 'B')
411690277Sobrien		switches[n_switches].validated = 1;
411790277Sobrien	    }
411818334Speter	  n_switches++;
411918334Speter	}
412018334Speter      else
412118334Speter	{
412290277Sobrien#ifdef HAVE_TARGET_OBJECT_SUFFIX
412390277Sobrien	  argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
412418334Speter#endif
412518334Speter
412690277Sobrien	  if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
412718334Speter	    {
412818334Speter	      perror_with_name (argv[i]);
412918334Speter	      error_count++;
413018334Speter	    }
413118334Speter	  else
413218334Speter	    {
413318334Speter	      infiles[n_infiles].language = spec_lang;
413418334Speter	      infiles[n_infiles++].name = argv[i];
413518334Speter	    }
413618334Speter	}
413718334Speter    }
413818334Speter
413918334Speter  if (n_infiles == last_language_n_infiles && spec_lang != 0)
414090277Sobrien    error ("warning: `-x %s' after last input file has no effect", spec_lang);
414118334Speter
414290277Sobrien  /* Ensure we only invoke each subprocess once.  */
414390277Sobrien  if (target_help_flag || print_help_list)
414490277Sobrien    {
414590277Sobrien      n_infiles = 1;
414690277Sobrien
414790277Sobrien      /* Create a dummy input file, so that we can pass --target-help on to
414890277Sobrien	 the various sub-processes.  */
414990277Sobrien      infiles[0].language = "c";
415090277Sobrien      infiles[0].name   = "help-dummy";
415190277Sobrien
415290277Sobrien      if (target_help_flag)
415390277Sobrien	{
415490277Sobrien	  switches[n_switches].part1     = "--target-help";
415590277Sobrien	  switches[n_switches].args      = 0;
415690277Sobrien	  switches[n_switches].live_cond = SWITCH_OK;
415790277Sobrien	  switches[n_switches].validated = 0;
415890277Sobrien
415990277Sobrien	  n_switches++;
416090277Sobrien	}
416190277Sobrien
416290277Sobrien      if (print_help_list)
416390277Sobrien	{
416490277Sobrien	  switches[n_switches].part1     = "--help";
416590277Sobrien	  switches[n_switches].args      = 0;
416690277Sobrien	  switches[n_switches].live_cond = SWITCH_OK;
416790277Sobrien	  switches[n_switches].validated = 0;
416890277Sobrien
416990277Sobrien	  n_switches++;
417090277Sobrien	}
417190277Sobrien    }
417290277Sobrien
417318334Speter  switches[n_switches].part1 = 0;
417418334Speter  infiles[n_infiles].name = 0;
417518334Speter}
417690277Sobrien
417790277Sobrien/* Store switches not filtered out by %{<S} in spec in COLLECT_GCC_OPTIONS
417890277Sobrien   and place that in the environment.  */
417990277Sobrien
418090277Sobrienstatic void
418190277Sobrienset_collect_gcc_options ()
418290277Sobrien{
418390277Sobrien  int i;
418490277Sobrien  int first_time;
418590277Sobrien
418690277Sobrien  /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
418790277Sobrien     the compiler.  */
418890277Sobrien  obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
418990277Sobrien		sizeof ("COLLECT_GCC_OPTIONS=") - 1);
419090277Sobrien
419190277Sobrien  first_time = TRUE;
419290277Sobrien  for (i = 0; (int) i < n_switches; i++)
419390277Sobrien    {
419490277Sobrien      const char *const *args;
419590277Sobrien      const char *p, *q;
419690277Sobrien      if (!first_time)
419790277Sobrien	obstack_grow (&collect_obstack, " ", 1);
419890277Sobrien
419990277Sobrien      first_time = FALSE;
420090277Sobrien
420190277Sobrien      /* Ignore elided switches.  */
420290277Sobrien      if (switches[i].live_cond == SWITCH_IGNORE)
420390277Sobrien	continue;
420490277Sobrien
420590277Sobrien      obstack_grow (&collect_obstack, "'-", 2);
420690277Sobrien      q = switches[i].part1;
420790277Sobrien      while ((p = strchr (q, '\'')))
420890277Sobrien	{
420990277Sobrien	  obstack_grow (&collect_obstack, q, p - q);
421090277Sobrien	  obstack_grow (&collect_obstack, "'\\''", 4);
421190277Sobrien	  q = ++p;
421290277Sobrien	}
421390277Sobrien      obstack_grow (&collect_obstack, q, strlen (q));
421490277Sobrien      obstack_grow (&collect_obstack, "'", 1);
421590277Sobrien
421690277Sobrien      for (args = switches[i].args; args && *args; args++)
421790277Sobrien	{
421890277Sobrien	  obstack_grow (&collect_obstack, " '", 2);
421990277Sobrien	  q = *args;
422090277Sobrien	  while ((p = strchr (q, '\'')))
422190277Sobrien	    {
422290277Sobrien	      obstack_grow (&collect_obstack, q, p - q);
422390277Sobrien	      obstack_grow (&collect_obstack, "'\\''", 4);
422490277Sobrien	      q = ++p;
422590277Sobrien	    }
422690277Sobrien	  obstack_grow (&collect_obstack, q, strlen (q));
422790277Sobrien	  obstack_grow (&collect_obstack, "'", 1);
422890277Sobrien	}
422990277Sobrien    }
423090277Sobrien  obstack_grow (&collect_obstack, "\0", 1);
423190277Sobrien  putenv (obstack_finish (&collect_obstack));
423290277Sobrien}
423318334Speter
423418334Speter/* Process a spec string, accumulating and running commands.  */
423518334Speter
423618334Speter/* These variables describe the input file name.
423718334Speter   input_file_number is the index on outfiles of this file,
423818334Speter   so that the output file name can be stored for later use by %o.
423918334Speter   input_basename is the start of the part of the input file
424018334Speter   sans all directory names, and basename_length is the number
424118334Speter   of characters starting there excluding the suffix .c or whatever.  */
424218334Speter
424352520Sobrienconst char *input_filename;
424418334Speterstatic int input_file_number;
424550599Sobriensize_t input_filename_length;
424618334Speterstatic int basename_length;
424790277Sobrienstatic int suffixed_basename_length;
424852520Sobrienstatic const char *input_basename;
424952520Sobrienstatic const char *input_suffix;
425090277Sobrienstatic struct stat input_stat;
425190277Sobrienstatic int input_stat_set;
425218334Speter
425390277Sobrien/* The compiler used to process the current input file.  */
425490277Sobrienstatic struct compiler *input_file_compiler;
425590277Sobrien
425618334Speter/* These are variables used within do_spec and do_spec_1.  */
425718334Speter
425818334Speter/* Nonzero if an arg has been started and not yet terminated
425918334Speter   (with space, tab or newline).  */
426018334Speterstatic int arg_going;
426118334Speter
426218334Speter/* Nonzero means %d or %g has been seen; the next arg to be terminated
426318334Speter   is a temporary file name.  */
426418334Speterstatic int delete_this_arg;
426518334Speter
426618334Speter/* Nonzero means %w has been seen; the next arg to be terminated
426718334Speter   is the output file name of this compilation.  */
426818334Speterstatic int this_is_output_file;
426918334Speter
427018334Speter/* Nonzero means %s has been seen; the next arg to be terminated
427118334Speter   is the name of a library file and we should try the standard
427218334Speter   search dirs for it.  */
427318334Speterstatic int this_is_library_file;
427418334Speter
427518334Speter/* Nonzero means that the input of this command is coming from a pipe.  */
427618334Speterstatic int input_from_pipe;
427718334Speter
427890277Sobrien/* Nonnull means substitute this for any suffix when outputting a switches
427990277Sobrien   arguments.  */
428090277Sobrienstatic const char *suffix_subst;
428190277Sobrien
428218334Speter/* Process the spec SPEC and run the commands specified therein.
428318334Speter   Returns 0 if the spec is successfully processed; -1 if failed.  */
428418334Speter
428550599Sobrienint
428618334Speterdo_spec (spec)
428752520Sobrien     const char *spec;
428818334Speter{
428918334Speter  int value;
429018334Speter
429118334Speter  clear_args ();
429218334Speter  arg_going = 0;
429318334Speter  delete_this_arg = 0;
429418334Speter  this_is_output_file = 0;
429518334Speter  this_is_library_file = 0;
429618334Speter  input_from_pipe = 0;
429790277Sobrien  suffix_subst = NULL;
429818334Speter
429990277Sobrien  value = do_spec_1 (spec, 0, NULL);
430018334Speter
430118334Speter  /* Force out any unfinished command.
430218334Speter     If -pipe, this forces out the last command if it ended in `|'.  */
430318334Speter  if (value == 0)
430418334Speter    {
430518334Speter      if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
430618334Speter	argbuf_index--;
430718334Speter
430890277Sobrien      set_collect_gcc_options ();
430990277Sobrien
431018334Speter      if (argbuf_index > 0)
431118334Speter	value = execute ();
431218334Speter    }
431318334Speter
431418334Speter  return value;
431518334Speter}
431618334Speter
431718334Speter/* Process the sub-spec SPEC as a portion of a larger spec.
431818334Speter   This is like processing a whole spec except that we do
431918334Speter   not initialize at the beginning and we do not supply a
432018334Speter   newline by default at the end.
432118334Speter   INSWITCH nonzero means don't process %-sequences in SPEC;
432218334Speter   in this case, % is treated as an ordinary character.
432318334Speter   This is used while substituting switches.
432418334Speter   INSWITCH nonzero also causes SPC not to terminate an argument.
432518334Speter
432618334Speter   Value is zero unless a line was finished
432718334Speter   and the command on that line reported an error.  */
432818334Speter
432918334Speterstatic int
433018334Speterdo_spec_1 (spec, inswitch, soft_matched_part)
433152520Sobrien     const char *spec;
433218334Speter     int inswitch;
433352520Sobrien     const char *soft_matched_part;
433418334Speter{
433590277Sobrien  const char *p = spec;
433690277Sobrien  int c;
433718334Speter  int i;
433852520Sobrien  const char *string;
433918334Speter  int value;
434018334Speter
434150599Sobrien  while ((c = *p++))
434218334Speter    /* If substituting a switch, treat all chars like letters.
434318334Speter       Otherwise, NL, SPC, TAB and % are special.  */
434418334Speter    switch (inswitch ? 'a' : c)
434518334Speter      {
434618334Speter      case '\n':
434718334Speter	/* End of line: finish any pending argument,
434818334Speter	   then run the pending command if one has been started.  */
434918334Speter	if (arg_going)
435018334Speter	  {
435118334Speter	    obstack_1grow (&obstack, 0);
435218334Speter	    string = obstack_finish (&obstack);
435318334Speter	    if (this_is_library_file)
435418334Speter	      string = find_file (string);
435518334Speter	    store_arg (string, delete_this_arg, this_is_output_file);
435618334Speter	    if (this_is_output_file)
435718334Speter	      outfiles[input_file_number] = string;
435818334Speter	  }
435918334Speter	arg_going = 0;
436018334Speter
436118334Speter	if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
436218334Speter	  {
436318334Speter	    for (i = 0; i < n_switches; i++)
436418334Speter	      if (!strcmp (switches[i].part1, "pipe"))
436518334Speter		break;
436618334Speter
436718334Speter	    /* A `|' before the newline means use a pipe here,
436818334Speter	       but only if -pipe was specified.
436918334Speter	       Otherwise, execute now and don't pass the `|' as an arg.  */
437018334Speter	    if (i < n_switches)
437118334Speter	      {
437218334Speter		input_from_pipe = 1;
437352520Sobrien		switches[i].validated = 1;
437418334Speter		break;
437518334Speter	      }
437618334Speter	    else
437718334Speter	      argbuf_index--;
437818334Speter	  }
437918334Speter
438090277Sobrien	set_collect_gcc_options ();
438190277Sobrien
438218334Speter	if (argbuf_index > 0)
438318334Speter	  {
438418334Speter	    value = execute ();
438518334Speter	    if (value)
438618334Speter	      return value;
438718334Speter	  }
438818334Speter	/* Reinitialize for a new command, and for a new argument.  */
438918334Speter	clear_args ();
439018334Speter	arg_going = 0;
439118334Speter	delete_this_arg = 0;
439218334Speter	this_is_output_file = 0;
439318334Speter	this_is_library_file = 0;
439418334Speter	input_from_pipe = 0;
439518334Speter	break;
439618334Speter
439718334Speter      case '|':
439818334Speter	/* End any pending argument.  */
439918334Speter	if (arg_going)
440018334Speter	  {
440118334Speter	    obstack_1grow (&obstack, 0);
440218334Speter	    string = obstack_finish (&obstack);
440318334Speter	    if (this_is_library_file)
440418334Speter	      string = find_file (string);
440518334Speter	    store_arg (string, delete_this_arg, this_is_output_file);
440618334Speter	    if (this_is_output_file)
440718334Speter	      outfiles[input_file_number] = string;
440818334Speter	  }
440918334Speter
441018334Speter	/* Use pipe */
441118334Speter	obstack_1grow (&obstack, c);
441218334Speter	arg_going = 1;
441318334Speter	break;
441418334Speter
441518334Speter      case '\t':
441618334Speter      case ' ':
441718334Speter	/* Space or tab ends an argument if one is pending.  */
441818334Speter	if (arg_going)
441918334Speter	  {
442018334Speter	    obstack_1grow (&obstack, 0);
442118334Speter	    string = obstack_finish (&obstack);
442218334Speter	    if (this_is_library_file)
442318334Speter	      string = find_file (string);
442418334Speter	    store_arg (string, delete_this_arg, this_is_output_file);
442518334Speter	    if (this_is_output_file)
442618334Speter	      outfiles[input_file_number] = string;
442718334Speter	  }
442818334Speter	/* Reinitialize for a new argument.  */
442918334Speter	arg_going = 0;
443018334Speter	delete_this_arg = 0;
443118334Speter	this_is_output_file = 0;
443218334Speter	this_is_library_file = 0;
443318334Speter	break;
443418334Speter
443518334Speter      case '%':
443618334Speter	switch (c = *p++)
443718334Speter	  {
443818334Speter	  case 0:
443990277Sobrien	    fatal ("invalid specification!  Bug in cc");
444018334Speter
444118334Speter	  case 'b':
444218334Speter	    obstack_grow (&obstack, input_basename, basename_length);
444318334Speter	    arg_going = 1;
444418334Speter	    break;
444518334Speter
444690277Sobrien	  case 'B':
444790277Sobrien	    obstack_grow (&obstack, input_basename, suffixed_basename_length);
444890277Sobrien	    arg_going = 1;
444990277Sobrien	    break;
445090277Sobrien
445118334Speter	  case 'd':
445218334Speter	    delete_this_arg = 2;
445318334Speter	    break;
445418334Speter
445518334Speter	  /* Dump out the directories specified with LIBRARY_PATH,
445618334Speter	     followed by the absolute directories
445718334Speter	     that we search for startfiles.  */
445818334Speter	  case 'D':
445918334Speter	    {
446018334Speter	      struct prefix_list *pl = startfile_prefixes.plist;
446150599Sobrien	      size_t bufsize = 100;
446218334Speter	      char *buffer = (char *) xmalloc (bufsize);
446318334Speter	      int idx;
446418334Speter
446518334Speter	      for (; pl; pl = pl->next)
446618334Speter		{
446718334Speter#ifdef RELATIVE_PREFIX_NOT_LINKDIR
446818334Speter		  /* Used on systems which record the specified -L dirs
446918334Speter		     and use them to search for dynamic linking.  */
447018334Speter		  /* Relative directories always come from -B,
447118334Speter		     and it is better not to use them for searching
447290277Sobrien		     at run time.  In particular, stage1 loses.  */
447390277Sobrien		  if (!IS_ABSOLUTE_PATHNAME (pl->prefix))
447418334Speter		    continue;
447518334Speter#endif
447618334Speter		  /* Try subdirectory if there is one.  */
447718334Speter		  if (multilib_dir != NULL)
447818334Speter		    {
447918334Speter		      if (machine_suffix)
448018334Speter			{
448118334Speter			  if (strlen (pl->prefix) + strlen (machine_suffix)
448218334Speter			      >= bufsize)
448318334Speter			    bufsize = (strlen (pl->prefix)
448418334Speter				       + strlen (machine_suffix)) * 2 + 1;
448518334Speter			  buffer = (char *) xrealloc (buffer, bufsize);
448618334Speter			  strcpy (buffer, pl->prefix);
448718334Speter			  strcat (buffer, machine_suffix);
448818334Speter			  if (is_directory (buffer, multilib_dir, 1))
448918334Speter			    {
449090277Sobrien			      do_spec_1 ("-L", 0, NULL);
449118334Speter#ifdef SPACE_AFTER_L_OPTION
449290277Sobrien			      do_spec_1 (" ", 0, NULL);
449318334Speter#endif
449490277Sobrien			      do_spec_1 (buffer, 1, NULL);
449590277Sobrien			      do_spec_1 (multilib_dir, 1, NULL);
449618334Speter			      /* Make this a separate argument.  */
449790277Sobrien			      do_spec_1 (" ", 0, NULL);
449818334Speter			    }
449918334Speter			}
450018334Speter		      if (!pl->require_machine_suffix)
450118334Speter			{
450218334Speter			  if (is_directory (pl->prefix, multilib_dir, 1))
450318334Speter			    {
450490277Sobrien			      do_spec_1 ("-L", 0, NULL);
450518334Speter#ifdef SPACE_AFTER_L_OPTION
450690277Sobrien			      do_spec_1 (" ", 0, NULL);
450718334Speter#endif
450890277Sobrien			      do_spec_1 (pl->prefix, 1, NULL);
450990277Sobrien			      do_spec_1 (multilib_dir, 1, NULL);
451018334Speter			      /* Make this a separate argument.  */
451190277Sobrien			      do_spec_1 (" ", 0, NULL);
451218334Speter			    }
451318334Speter			}
451418334Speter		    }
451518334Speter		  if (machine_suffix)
451618334Speter		    {
451718334Speter		      if (is_directory (pl->prefix, machine_suffix, 1))
451818334Speter			{
451990277Sobrien			  do_spec_1 ("-L", 0, NULL);
452018334Speter#ifdef SPACE_AFTER_L_OPTION
452190277Sobrien			  do_spec_1 (" ", 0, NULL);
452218334Speter#endif
452390277Sobrien			  do_spec_1 (pl->prefix, 1, NULL);
452418334Speter			  /* Remove slash from machine_suffix.  */
452518334Speter			  if (strlen (machine_suffix) >= bufsize)
452618334Speter			    bufsize = strlen (machine_suffix) * 2 + 1;
452718334Speter			  buffer = (char *) xrealloc (buffer, bufsize);
452818334Speter			  strcpy (buffer, machine_suffix);
452918334Speter			  idx = strlen (buffer);
453052520Sobrien			  if (IS_DIR_SEPARATOR (buffer[idx - 1]))
453118334Speter			    buffer[idx - 1] = 0;
453290277Sobrien			  do_spec_1 (buffer, 1, NULL);
453318334Speter			  /* Make this a separate argument.  */
453490277Sobrien			  do_spec_1 (" ", 0, NULL);
453518334Speter			}
453618334Speter		    }
453718334Speter		  if (!pl->require_machine_suffix)
453818334Speter		    {
453918334Speter		      if (is_directory (pl->prefix, "", 1))
454018334Speter			{
454190277Sobrien			  do_spec_1 ("-L", 0, NULL);
454218334Speter#ifdef SPACE_AFTER_L_OPTION
454390277Sobrien			  do_spec_1 (" ", 0, NULL);
454418334Speter#endif
454518334Speter			  /* Remove slash from pl->prefix.  */
454618334Speter			  if (strlen (pl->prefix) >= bufsize)
454718334Speter			    bufsize = strlen (pl->prefix) * 2 + 1;
454818334Speter			  buffer = (char *) xrealloc (buffer, bufsize);
454918334Speter			  strcpy (buffer, pl->prefix);
455018334Speter			  idx = strlen (buffer);
455152520Sobrien			  if (IS_DIR_SEPARATOR (buffer[idx - 1]))
455218334Speter			    buffer[idx - 1] = 0;
455390277Sobrien			  do_spec_1 (buffer, 1, NULL);
455418334Speter			  /* Make this a separate argument.  */
455590277Sobrien			  do_spec_1 (" ", 0, NULL);
455618334Speter			}
455718334Speter		    }
455818334Speter		}
455918334Speter	      free (buffer);
456018334Speter	    }
456118334Speter	    break;
456218334Speter
456318334Speter	  case 'e':
456452520Sobrien	    /* %efoo means report an error with `foo' as error message
456518334Speter	       and don't execute any more commands for this file.  */
456618334Speter	    {
456752520Sobrien	      const char *q = p;
456818334Speter	      char *buf;
456990277Sobrien	      while (*p != 0 && *p != '\n')
457090277Sobrien		p++;
457118334Speter	      buf = (char *) alloca (p - q + 1);
457218334Speter	      strncpy (buf, q, p - q);
457318334Speter	      buf[p - q] = 0;
457490277Sobrien	      error ("%s", buf);
457518334Speter	      return -1;
457618334Speter	    }
457718334Speter	    break;
457890277Sobrien	  case 'n':
457990277Sobrien	    /* %nfoo means report an notice with `foo' on stderr.  */
458090277Sobrien	    {
458190277Sobrien	      const char *q = p;
458290277Sobrien	      char *buf;
458390277Sobrien	      while (*p != 0 && *p != '\n')
458490277Sobrien		p++;
458590277Sobrien	      buf = (char *) alloca (p - q + 1);
458690277Sobrien	      strncpy (buf, q, p - q);
458790277Sobrien	      buf[p - q] = 0;
458890277Sobrien	      notice ("%s\n", buf);
458990277Sobrien	      if (*p)
459090277Sobrien		p++;
459190277Sobrien	    }
459290277Sobrien	    break;
459318334Speter
459490277Sobrien	  case 'j':
459590277Sobrien	    {
459690277Sobrien	      struct stat st;
459790277Sobrien
459890277Sobrien	      /* If save_temps_flag is off, and the HOST_BIT_BUCKET is defined,
459990277Sobrien		 and it is not a directory, and it is writable, use it.
460090277Sobrien		 Otherwise, fall through and treat this like any other
460190277Sobrien		 temporary file.  */
460290277Sobrien
460390277Sobrien	      if ((!save_temps_flag)
460490277Sobrien		  && (stat (HOST_BIT_BUCKET, &st) == 0) && (!S_ISDIR (st.st_mode))
460590277Sobrien		  && (access (HOST_BIT_BUCKET, W_OK) == 0))
460690277Sobrien		{
460790277Sobrien		  obstack_grow (&obstack, HOST_BIT_BUCKET,
460890277Sobrien				strlen (HOST_BIT_BUCKET));
460990277Sobrien		  delete_this_arg = 0;
461090277Sobrien		  arg_going = 1;
461190277Sobrien		  break;
461290277Sobrien		}
461390277Sobrien	    }
461418334Speter	  case 'g':
461518334Speter	  case 'u':
461618334Speter	  case 'U':
461718334Speter	      {
461818334Speter		struct temp_name *t;
461950599Sobrien		int suffix_length;
462052520Sobrien		const char *suffix = p;
462190277Sobrien		char *saved_suffix = NULL;
462218334Speter
462390277Sobrien		while (*p == '.' || ISALPHA ((unsigned char) *p))
462490277Sobrien		  p++;
462590277Sobrien		suffix_length = p - suffix;
462650599Sobrien		if (p[0] == '%' && p[1] == 'O')
462750599Sobrien		  {
462850599Sobrien		    p += 2;
462950599Sobrien		    /* We don't support extra suffix characters after %O.  */
463090277Sobrien		    if (*p == '.' || ISALPHA ((unsigned char) *p))
463150599Sobrien		      abort ();
463290277Sobrien		    if (suffix_length == 0)
463390277Sobrien		      suffix = TARGET_OBJECT_SUFFIX;
463490277Sobrien		    else
463590277Sobrien		      {
463690277Sobrien			saved_suffix
463790277Sobrien			  = (char *) xmalloc (suffix_length
463890277Sobrien					      + strlen (TARGET_OBJECT_SUFFIX));
463990277Sobrien			strncpy (saved_suffix, suffix, suffix_length);
464090277Sobrien			strcpy (saved_suffix + suffix_length,
464190277Sobrien				TARGET_OBJECT_SUFFIX);
464290277Sobrien		      }
464390277Sobrien		    suffix_length += strlen (TARGET_OBJECT_SUFFIX);
464450599Sobrien		  }
464590277Sobrien
464690277Sobrien		/* If the input_filename has the same suffix specified
464790277Sobrien		   for the %g, %u, or %U, and -save-temps is specified,
464890277Sobrien		   we could end up using that file as an intermediate
464990277Sobrien		   thus clobbering the user's source file (.e.g.,
465090277Sobrien		   gcc -save-temps foo.s would clobber foo.s with the
465190277Sobrien		   output of cpp0).  So check for this condition and
465290277Sobrien		   generate a temp file as the intermediate.  */
465390277Sobrien
465490277Sobrien		if (save_temps_flag)
465550599Sobrien		  {
465690277Sobrien		    temp_filename_length = basename_length + suffix_length;
465790277Sobrien		    temp_filename = alloca (temp_filename_length + 1);
465890277Sobrien		    strncpy ((char *) temp_filename, input_basename, basename_length);
465990277Sobrien		    strncpy ((char *) temp_filename + basename_length, suffix,
466090277Sobrien		    	     suffix_length);
466190277Sobrien		    *((char *) temp_filename + temp_filename_length) = '\0';
466290277Sobrien		    if (strcmp (temp_filename, input_filename) != 0)
466390277Sobrien		      {
466490277Sobrien		      	struct stat st_temp;
466590277Sobrien
466690277Sobrien		      	/* Note, set_input() resets input_stat_set to 0.  */
466790277Sobrien		      	if (input_stat_set == 0)
466890277Sobrien		      	  {
466990277Sobrien		      	    input_stat_set = stat (input_filename, &input_stat);
467090277Sobrien		      	    if (input_stat_set >= 0)
467190277Sobrien		      	      input_stat_set = 1;
467290277Sobrien		      	  }
467390277Sobrien
467490277Sobrien		      	/* If we have the stat for the input_filename
467590277Sobrien		      	   and we can do the stat for the temp_filename
467690277Sobrien		      	   then the they could still refer to the same
467790277Sobrien		      	   file if st_dev/st_ino's are the same.  */
467890277Sobrien
467990277Sobrien			if (input_stat_set != 1
468090277Sobrien			    || stat (temp_filename, &st_temp) < 0
468190277Sobrien			    || input_stat.st_dev != st_temp.st_dev
468290277Sobrien			    || input_stat.st_ino != st_temp.st_ino)
468390277Sobrien 		      	  {
468490277Sobrien			    temp_filename = save_string (temp_filename,
468590277Sobrien							 temp_filename_length + 1);
468690277Sobrien			    obstack_grow (&obstack, temp_filename,
468790277Sobrien			    			    temp_filename_length);
468890277Sobrien			    arg_going = 1;
468990277Sobrien			    break;
469090277Sobrien			  }
469190277Sobrien		      }
469250599Sobrien		  }
469350599Sobrien
469418334Speter		/* See if we already have an association of %g/%u/%U and
469518334Speter		   suffix.  */
469618334Speter		for (t = temp_names; t; t = t->next)
469750599Sobrien		  if (t->length == suffix_length
469850599Sobrien		      && strncmp (t->suffix, suffix, suffix_length) == 0
469918334Speter		      && t->unique == (c != 'g'))
470018334Speter		    break;
470118334Speter
470290277Sobrien		/* Make a new association if needed.  %u and %j
470390277Sobrien		   require one.  */
470490277Sobrien		if (t == 0 || c == 'u' || c == 'j')
470518334Speter		  {
470618334Speter		    if (t == 0)
470718334Speter		      {
470818334Speter			t = (struct temp_name *) xmalloc (sizeof (struct temp_name));
470918334Speter			t->next = temp_names;
471018334Speter			temp_names = t;
471118334Speter		      }
471250599Sobrien		    t->length = suffix_length;
471390277Sobrien		    if (saved_suffix)
471490277Sobrien		      {
471590277Sobrien			t->suffix = saved_suffix;
471690277Sobrien			saved_suffix = NULL;
471790277Sobrien		      }
471890277Sobrien		    else
471990277Sobrien		      t->suffix = save_string (suffix, suffix_length);
472018334Speter		    t->unique = (c != 'g');
472150599Sobrien		    temp_filename = make_temp_file (t->suffix);
472250599Sobrien		    temp_filename_length = strlen (temp_filename);
472318334Speter		    t->filename = temp_filename;
472418334Speter		    t->filename_length = temp_filename_length;
472518334Speter		  }
472618334Speter
472790277Sobrien		if (saved_suffix)
472890277Sobrien		  free (saved_suffix);
472990277Sobrien
473018334Speter		obstack_grow (&obstack, t->filename, t->filename_length);
473118334Speter		delete_this_arg = 1;
473218334Speter	      }
473318334Speter	    arg_going = 1;
473418334Speter	    break;
473518334Speter
473618334Speter	  case 'i':
473718334Speter	    obstack_grow (&obstack, input_filename, input_filename_length);
473818334Speter	    arg_going = 1;
473918334Speter	    break;
474018334Speter
474118334Speter	  case 'I':
474218334Speter	    {
474318334Speter	      struct prefix_list *pl = include_prefixes.plist;
474418334Speter
474518334Speter	      if (gcc_exec_prefix)
474618334Speter		{
474790277Sobrien		  do_spec_1 ("-iprefix", 1, NULL);
474818334Speter		  /* Make this a separate argument.  */
474990277Sobrien		  do_spec_1 (" ", 0, NULL);
475090277Sobrien		  do_spec_1 (gcc_exec_prefix, 1, NULL);
475190277Sobrien		  do_spec_1 (" ", 0, NULL);
475218334Speter		}
475318334Speter
475418334Speter	      for (; pl; pl = pl->next)
475518334Speter		{
475690277Sobrien		  do_spec_1 ("-isystem", 1, NULL);
475718334Speter		  /* Make this a separate argument.  */
475890277Sobrien		  do_spec_1 (" ", 0, NULL);
475990277Sobrien		  do_spec_1 (pl->prefix, 1, NULL);
476090277Sobrien		  do_spec_1 (" ", 0, NULL);
476118334Speter		}
476218334Speter	    }
476318334Speter	    break;
476418334Speter
476518334Speter	  case 'o':
476652520Sobrien	    {
476752520Sobrien	      int max = n_infiles;
476852520Sobrien	      max += lang_specific_extra_outfiles;
476918334Speter
477052520Sobrien	      for (i = 0; i < max; i++)
477152520Sobrien		if (outfiles[i])
477252520Sobrien		  store_arg (outfiles[i], 0, 0);
477352520Sobrien	      break;
477452520Sobrien	    }
477552520Sobrien
477618334Speter	  case 'O':
477790277Sobrien	    obstack_grow (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
477818334Speter	    arg_going = 1;
477918334Speter	    break;
478018334Speter
478118334Speter	  case 's':
478218334Speter	    this_is_library_file = 1;
478318334Speter	    break;
478418334Speter
478518334Speter	  case 'w':
478618334Speter	    this_is_output_file = 1;
478718334Speter	    break;
478818334Speter
478918334Speter	  case 'W':
479018334Speter	    {
479150599Sobrien	      int cur_index = argbuf_index;
479218334Speter	      /* Handle the {...} following the %W.  */
479318334Speter	      if (*p != '{')
479418334Speter		abort ();
479518334Speter	      p = handle_braces (p + 1);
479618334Speter	      if (p == 0)
479718334Speter		return -1;
479818334Speter	      /* If any args were output, mark the last one for deletion
479918334Speter		 on failure.  */
480050599Sobrien	      if (argbuf_index != cur_index)
480118334Speter		record_temp_file (argbuf[argbuf_index - 1], 0, 1);
480218334Speter	      break;
480318334Speter	    }
480418334Speter
480518334Speter	  /* %x{OPTION} records OPTION for %X to output.  */
480618334Speter	  case 'x':
480718334Speter	    {
480852520Sobrien	      const char *p1 = p;
480918334Speter	      char *string;
481018334Speter
481118334Speter	      /* Skip past the option value and make a copy.  */
481218334Speter	      if (*p != '{')
481318334Speter		abort ();
481418334Speter	      while (*p++ != '}')
481518334Speter		;
481618334Speter	      string = save_string (p1 + 1, p - p1 - 2);
481718334Speter
481818334Speter	      /* See if we already recorded this option.  */
481918334Speter	      for (i = 0; i < n_linker_options; i++)
482018334Speter		if (! strcmp (string, linker_options[i]))
482118334Speter		  {
482218334Speter		    free (string);
482318334Speter		    return 0;
482418334Speter		  }
482518334Speter
482618334Speter	      /* This option is new; add it.  */
482750599Sobrien	      add_linker_option (string, strlen (string));
482818334Speter	    }
482918334Speter	    break;
483018334Speter
483118334Speter	  /* Dump out the options accumulated previously using %x.  */
483218334Speter	  case 'X':
483318334Speter	    for (i = 0; i < n_linker_options; i++)
483418334Speter	      {
483590277Sobrien		do_spec_1 (linker_options[i], 1, NULL);
483618334Speter		/* Make each accumulated option a separate argument.  */
483790277Sobrien		do_spec_1 (" ", 0, NULL);
483818334Speter	      }
483918334Speter	    break;
484018334Speter
484118334Speter	  /* Dump out the options accumulated previously using -Wa,.  */
484218334Speter	  case 'Y':
484318334Speter	    for (i = 0; i < n_assembler_options; i++)
484418334Speter	      {
484590277Sobrien		do_spec_1 (assembler_options[i], 1, NULL);
484618334Speter		/* Make each accumulated option a separate argument.  */
484790277Sobrien		do_spec_1 (" ", 0, NULL);
484818334Speter	      }
484918334Speter	    break;
485018334Speter
485118334Speter	  /* Dump out the options accumulated previously using -Wp,.  */
485218334Speter	  case 'Z':
485318334Speter	    for (i = 0; i < n_preprocessor_options; i++)
485418334Speter	      {
485590277Sobrien		do_spec_1 (preprocessor_options[i], 1, NULL);
485618334Speter		/* Make each accumulated option a separate argument.  */
485790277Sobrien		do_spec_1 (" ", 0, NULL);
485818334Speter	      }
485918334Speter	    break;
486018334Speter
486118334Speter	    /* Here are digits and numbers that just process
486218334Speter	       a certain constant string as a spec.  */
486318334Speter
486418334Speter	  case '1':
486590277Sobrien	    value = do_spec_1 (cc1_spec, 0, NULL);
486618334Speter	    if (value != 0)
486718334Speter	      return value;
486818334Speter	    break;
486918334Speter
487018334Speter	  case '2':
487190277Sobrien	    value = do_spec_1 (cc1plus_spec, 0, NULL);
487218334Speter	    if (value != 0)
487318334Speter	      return value;
487418334Speter	    break;
487518334Speter
487618334Speter	  case 'a':
487790277Sobrien	    value = do_spec_1 (asm_spec, 0, NULL);
487818334Speter	    if (value != 0)
487918334Speter	      return value;
488018334Speter	    break;
488118334Speter
488218334Speter	  case 'A':
488390277Sobrien	    value = do_spec_1 (asm_final_spec, 0, NULL);
488418334Speter	    if (value != 0)
488518334Speter	      return value;
488618334Speter	    break;
488718334Speter
488818334Speter	  case 'c':
488990277Sobrien	    value = do_spec_1 (signed_char_spec, 0, NULL);
489018334Speter	    if (value != 0)
489118334Speter	      return value;
489218334Speter	    break;
489318334Speter
489418334Speter	  case 'C':
489590277Sobrien	    {
489690277Sobrien	      const char *const spec
489790277Sobrien		= (input_file_compiler->cpp_spec
489890277Sobrien		   ? input_file_compiler->cpp_spec
489990277Sobrien		   : cpp_spec);
490090277Sobrien	      value = do_spec_1 (spec, 0, NULL);
490190277Sobrien	      if (value != 0)
490290277Sobrien		return value;
490390277Sobrien	    }
490418334Speter	    break;
490518334Speter
490618334Speter	  case 'E':
490790277Sobrien	    value = do_spec_1 (endfile_spec, 0, NULL);
490818334Speter	    if (value != 0)
490918334Speter	      return value;
491018334Speter	    break;
491118334Speter
491218334Speter	  case 'l':
491390277Sobrien	    value = do_spec_1 (link_spec, 0, NULL);
491418334Speter	    if (value != 0)
491518334Speter	      return value;
491618334Speter	    break;
491718334Speter
491818334Speter	  case 'L':
491990277Sobrien	    value = do_spec_1 (lib_spec, 0, NULL);
492018334Speter	    if (value != 0)
492118334Speter	      return value;
492218334Speter	    break;
492318334Speter
492418334Speter	  case 'G':
492590277Sobrien	    value = do_spec_1 (libgcc_spec, 0, NULL);
492618334Speter	    if (value != 0)
492718334Speter	      return value;
492818334Speter	    break;
492918334Speter
493090277Sobrien	  case 'M':
493190277Sobrien	    if (multilib_dir && strcmp (multilib_dir, ".") != 0)
493290277Sobrien	      {
493390277Sobrien		char *p;
493490277Sobrien		const char *q;
493590277Sobrien		size_t len;
493690277Sobrien
493790277Sobrien		len = strlen (multilib_dir);
493890277Sobrien		obstack_blank (&obstack, len + 1);
493990277Sobrien		p = obstack_next_free (&obstack) - (len + 1);
494090277Sobrien
494190277Sobrien		*p++ = '_';
494290277Sobrien		for (q = multilib_dir; *q ; ++q, ++p)
494390277Sobrien		  *p = (IS_DIR_SEPARATOR (*q) ? '_' : *q);
494490277Sobrien	      }
494590277Sobrien	    break;
494690277Sobrien
494718334Speter	  case 'p':
494818334Speter	    {
494918334Speter	      char *x = (char *) alloca (strlen (cpp_predefines) + 1);
495018334Speter	      char *buf = x;
495190277Sobrien	      const char *y;
495218334Speter
495318334Speter	      /* Copy all of the -D options in CPP_PREDEFINES into BUF.  */
495418334Speter	      y = cpp_predefines;
495518334Speter	      while (*y != 0)
495618334Speter		{
495718334Speter		  if (! strncmp (y, "-D", 2))
495818334Speter		    /* Copy the whole option.  */
495918334Speter		    while (*y && *y != ' ' && *y != '\t')
496018334Speter		      *x++ = *y++;
496118334Speter		  else if (*y == ' ' || *y == '\t')
496218334Speter		    /* Copy whitespace to the result.  */
496318334Speter		    *x++ = *y++;
496418334Speter		  /* Don't copy other options.  */
496518334Speter		  else
496618334Speter		    y++;
496718334Speter		}
496818334Speter
496918334Speter	      *x = 0;
497018334Speter
497190277Sobrien	      value = do_spec_1 (buf, 0, NULL);
497218334Speter	      if (value != 0)
497318334Speter		return value;
497418334Speter	    }
497518334Speter	    break;
497618334Speter
497718334Speter	  case 'P':
497818334Speter	    {
497918334Speter	      char *x = (char *) alloca (strlen (cpp_predefines) * 4 + 1);
498018334Speter	      char *buf = x;
498190277Sobrien	      const char *y;
498218334Speter
498318334Speter	      /* Copy all of CPP_PREDEFINES into BUF,
498490277Sobrien		 but force them all into the reserved name space if they
498590277Sobrien		 aren't already there.  The reserved name space is all
498690277Sobrien		 identifiers beginning with two underscores or with one
498790277Sobrien		 underscore and a capital letter.  We do the forcing by
498890277Sobrien		 adding up to two underscores to the beginning and end
498990277Sobrien		 of each symbol. e.g. mips, _mips, mips_, and _mips_ all
499090277Sobrien		 become __mips__.  */
499118334Speter	      y = cpp_predefines;
499218334Speter	      while (*y != 0)
499318334Speter		{
499418334Speter		  if (! strncmp (y, "-D", 2))
499518334Speter		    {
499618334Speter		      int flag = 0;
499718334Speter
499818334Speter		      *x++ = *y++;
499918334Speter		      *x++ = *y++;
500018334Speter
500118334Speter		      if (*y != '_'
500290277Sobrien			  || (*(y + 1) != '_'
500390277Sobrien			      && ! ISUPPER ((unsigned char) *(y + 1))))
500490277Sobrien			{
500518334Speter			  /* Stick __ at front of macro name.  */
500690277Sobrien			  if (*y != '_')
500790277Sobrien			    *x++ = '_';
500818334Speter			  *x++ = '_';
500918334Speter			  /* Arrange to stick __ at the end as well.  */
501018334Speter			  flag = 1;
501118334Speter			}
501218334Speter
501318334Speter		      /* Copy the macro name.  */
501418334Speter		      while (*y && *y != '=' && *y != ' ' && *y != '\t')
501518334Speter			*x++ = *y++;
501618334Speter
501718334Speter		      if (flag)
501890277Sobrien			{
501990277Sobrien			  if (x[-1] != '_')
502090277Sobrien			    {
502190277Sobrien			      if (x[-2] != '_')
502290277Sobrien				*x++ = '_';
502390277Sobrien			      *x++ = '_';
502490277Sobrien			    }
502518334Speter			}
502618334Speter
502718334Speter		      /* Copy the value given, if any.  */
502818334Speter		      while (*y && *y != ' ' && *y != '\t')
502918334Speter			*x++ = *y++;
503018334Speter		    }
503118334Speter		  else if (*y == ' ' || *y == '\t')
503218334Speter		    /* Copy whitespace to the result.  */
503318334Speter		    *x++ = *y++;
503418334Speter		  /* Don't copy -A options  */
503518334Speter		  else
503618334Speter		    y++;
503718334Speter		}
503818334Speter	      *x++ = ' ';
503918334Speter
504018334Speter	      /* Copy all of CPP_PREDEFINES into BUF,
504118334Speter		 but put __ after every -D.  */
504218334Speter	      y = cpp_predefines;
504318334Speter	      while (*y != 0)
504418334Speter		{
504518334Speter		  if (! strncmp (y, "-D", 2))
504618334Speter		    {
504718334Speter		      y += 2;
504818334Speter
504918334Speter		      if (*y != '_'
505090277Sobrien			  || (*(y + 1) != '_'
505190277Sobrien			      && ! ISUPPER ((unsigned char) *(y + 1))))
505290277Sobrien			{
505318334Speter			  /* Stick -D__ at front of macro name.  */
505418334Speter			  *x++ = '-';
505518334Speter			  *x++ = 'D';
505690277Sobrien			  if (*y != '_')
505790277Sobrien			    *x++ = '_';
505818334Speter			  *x++ = '_';
505918334Speter
506018334Speter			  /* Copy the macro name.  */
506118334Speter			  while (*y && *y != '=' && *y != ' ' && *y != '\t')
506218334Speter			    *x++ = *y++;
506318334Speter
506418334Speter			  /* Copy the value given, if any.  */
506518334Speter			  while (*y && *y != ' ' && *y != '\t')
506618334Speter			    *x++ = *y++;
506718334Speter			}
506818334Speter		      else
506918334Speter			{
507018334Speter			  /* Do not copy this macro - we have just done it before */
507118334Speter			  while (*y && *y != ' ' && *y != '\t')
507218334Speter			    y++;
507318334Speter			}
507418334Speter		    }
507518334Speter		  else if (*y == ' ' || *y == '\t')
507618334Speter		    /* Copy whitespace to the result.  */
507718334Speter		    *x++ = *y++;
507890277Sobrien		  /* Don't copy -A options.  */
507918334Speter		  else
508018334Speter		    y++;
508118334Speter		}
508218334Speter	      *x++ = ' ';
508318334Speter
508418334Speter	      /* Copy all of the -A options in CPP_PREDEFINES into BUF.  */
508518334Speter	      y = cpp_predefines;
508618334Speter	      while (*y != 0)
508718334Speter		{
508818334Speter		  if (! strncmp (y, "-A", 2))
508918334Speter		    /* Copy the whole option.  */
509018334Speter		    while (*y && *y != ' ' && *y != '\t')
509118334Speter		      *x++ = *y++;
509218334Speter		  else if (*y == ' ' || *y == '\t')
509318334Speter		    /* Copy whitespace to the result.  */
509418334Speter		    *x++ = *y++;
509518334Speter		  /* Don't copy other options.  */
509618334Speter		  else
509718334Speter		    y++;
509818334Speter		}
509918334Speter
510018334Speter	      *x = 0;
510118334Speter
510290277Sobrien	      value = do_spec_1 (buf, 0, NULL);
510318334Speter	      if (value != 0)
510418334Speter		return value;
510518334Speter	    }
510618334Speter	    break;
510718334Speter
510818334Speter	  case 'S':
510990277Sobrien	    value = do_spec_1 (startfile_spec, 0, NULL);
511018334Speter	    if (value != 0)
511118334Speter	      return value;
511218334Speter	    break;
511318334Speter
511418334Speter	    /* Here we define characters other than letters and digits.  */
511518334Speter
511618334Speter	  case '{':
511718334Speter	    p = handle_braces (p);
511818334Speter	    if (p == 0)
511918334Speter	      return -1;
512018334Speter	    break;
512118334Speter
512218334Speter	  case '%':
512318334Speter	    obstack_1grow (&obstack, '%');
512418334Speter	    break;
512518334Speter
512690277Sobrien         case '.':
512790277Sobrien	   {
512890277Sobrien	     unsigned len = 0;
512990277Sobrien
513090277Sobrien	     while (p[len] && p[len] != ' ' && p[len] != '%')
513190277Sobrien	       len++;
513290277Sobrien             suffix_subst = save_string (p - 1, len + 1);
513390277Sobrien             p += len;
513490277Sobrien           }
513590277Sobrien	   break;
513690277Sobrien
513718334Speter	  case '*':
513890277Sobrien	    if (soft_matched_part)
513990277Sobrien	      {
514090277Sobrien		do_spec_1 (soft_matched_part, 1, NULL);
514190277Sobrien		do_spec_1 (" ", 0, NULL);
514290277Sobrien	      }
514390277Sobrien	    else
514490277Sobrien	      /* Catch the case where a spec string contains something like
514590277Sobrien		 '%{foo:%*}'.  ie there is no * in the pattern on the left
514690277Sobrien		 hand side of the :.  */
514790277Sobrien	      error ("spec failure: '%%*' has not been initialized by pattern match");
514818334Speter	    break;
514918334Speter
515018334Speter	    /* Process a string found as the value of a spec given by name.
515118334Speter	       This feature allows individual machine descriptions
515218334Speter	       to add and use their own specs.
515318334Speter	       %[...] modifies -D options the way %P does;
515418334Speter	       %(...) uses the spec unmodified.  */
515550599Sobrien	  case '[':
515690277Sobrien	    error ("warning: use of obsolete %%[ operator in specs");
515718334Speter	  case '(':
515818334Speter	    {
515952520Sobrien	      const char *name = p;
516018334Speter	      struct spec_list *sl;
516118334Speter	      int len;
516218334Speter
516318334Speter	      /* The string after the S/P is the name of a spec that is to be
516450599Sobrien		 processed.  */
516518334Speter	      while (*p && *p != ')' && *p != ']')
516618334Speter		p++;
516718334Speter
516890277Sobrien	      /* See if it's in the list.  */
516918334Speter	      for (len = p - name, sl = specs; sl; sl = sl->next)
517050599Sobrien		if (sl->name_len == len && !strncmp (sl->name, name, len))
517118334Speter		  {
517250599Sobrien		    name = *(sl->ptr_spec);
517350599Sobrien#ifdef DEBUG_SPECS
517452520Sobrien		    notice ("Processing spec %c%s%c, which is '%s'\n",
517552520Sobrien			    c, sl->name, (c == '(') ? ')' : ']', name);
517650599Sobrien#endif
517718334Speter		    break;
517818334Speter		  }
517918334Speter
518018334Speter	      if (sl)
518118334Speter		{
518218334Speter		  if (c == '(')
518318334Speter		    {
518490277Sobrien		      value = do_spec_1 (name, 0, NULL);
518518334Speter		      if (value != 0)
518618334Speter			return value;
518718334Speter		    }
518818334Speter		  else
518918334Speter		    {
519018334Speter		      char *x = (char *) alloca (strlen (name) * 2 + 1);
519118334Speter		      char *buf = x;
519252520Sobrien		      const char *y = name;
519350599Sobrien		      int flag = 0;
519418334Speter
519518334Speter		      /* Copy all of NAME into BUF, but put __ after
519690277Sobrien			 every -D and at the end of each arg.  */
519718334Speter		      while (1)
519818334Speter			{
519918334Speter			  if (! strncmp (y, "-D", 2))
520018334Speter			    {
520118334Speter			      *x++ = '-';
520218334Speter			      *x++ = 'D';
520318334Speter			      *x++ = '_';
520418334Speter			      *x++ = '_';
520518334Speter			      y += 2;
520650599Sobrien			      flag = 1;
520750599Sobrien			      continue;
520818334Speter			    }
520990277Sobrien			  else if (flag
521090277Sobrien				   && (*y == ' ' || *y == '\t' || *y == '='
521190277Sobrien				       || *y == '}' || *y == 0))
521218334Speter			    {
521318334Speter			      *x++ = '_';
521418334Speter			      *x++ = '_';
521550599Sobrien			      flag = 0;
521618334Speter			    }
521790277Sobrien			  if (*y == 0)
521850599Sobrien			    break;
521918334Speter			  else
522018334Speter			    *x++ = *y++;
522118334Speter			}
522218334Speter		      *x = 0;
522318334Speter
522490277Sobrien		      value = do_spec_1 (buf, 0, NULL);
522518334Speter		      if (value != 0)
522618334Speter			return value;
522718334Speter		    }
522818334Speter		}
522918334Speter
523018334Speter	      /* Discard the closing paren or bracket.  */
523118334Speter	      if (*p)
523218334Speter		p++;
523318334Speter	    }
523418334Speter	    break;
523518334Speter
523618334Speter	  case 'v':
523718334Speter	    {
523818334Speter	      int c1 = *p++;  /* Select first or second version number.  */
523990277Sobrien	      const char *v = compiler_version;
524090277Sobrien	      const char *q;
524190277Sobrien	      static const char zeroc = '0';
524250599Sobrien
524350599Sobrien	      /* The format of the version string is
524450599Sobrien		 ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */
524550599Sobrien
524650599Sobrien	      /* Ignore leading non-digits.  i.e. "foo-" in "foo-2.7.2".  */
524750599Sobrien	      while (! ISDIGIT (*v))
524850599Sobrien		v++;
524950599Sobrien	      if (v > compiler_version && v[-1] != '-')
525050599Sobrien		abort ();
525150599Sobrien
525218334Speter	      /* If desired, advance to second version number.  */
525390277Sobrien	      if (c1 >= '2')
525418334Speter		{
525550599Sobrien		  /* Set V after the first period.  */
525650599Sobrien		  while (ISDIGIT (*v))
525718334Speter		    v++;
525850599Sobrien		  if (*v != '.')
525950599Sobrien		    abort ();
526050599Sobrien		  v++;
526118334Speter		}
526250599Sobrien
526390277Sobrien	      /* If desired, advance to third version number.
526490277Sobrien                 But don't complain if it's not present */
526590277Sobrien	      if (c1 == '3')
526690277Sobrien		{
526790277Sobrien		  /* Set V after the second period.  */
526890277Sobrien		  while (ISDIGIT (*v))
526990277Sobrien		    v++;
527090277Sobrien		  if ((*v != 0) && (*v != ' ') && (*v != '.') && (*v != '-'))
527190277Sobrien		    abort ();
527290277Sobrien		  if (*v != 0)
527390277Sobrien		    v++;
527490277Sobrien		}
527590277Sobrien
527618334Speter	      /* Set Q at the next period or at the end.  */
527718334Speter	      q = v;
527850599Sobrien	      while (ISDIGIT (*q))
527918334Speter		q++;
528090277Sobrien	      if (*q != 0 && q > v && *q != ' ' && *q != '.' && *q != '-')
528150599Sobrien		abort ();
528250599Sobrien
528390277Sobrien	      if (q > v)
528490277Sobrien		/* Put that part into the command.  */
528590277Sobrien		obstack_grow (&obstack, v, q - v);
528690277Sobrien	      else
528790277Sobrien		/* Default to "0" */
528890277Sobrien		obstack_grow (&obstack, &zeroc, 1);
528918334Speter	      arg_going = 1;
529018334Speter	    }
529118334Speter	    break;
529218334Speter
529318334Speter	  case '|':
529418334Speter	    if (input_from_pipe)
529590277Sobrien	      do_spec_1 ("-", 0, NULL);
529618334Speter	    break;
529718334Speter
529818334Speter	  default:
529990277Sobrien	    error ("spec failure: unrecognized spec option '%c'", c);
530090277Sobrien	    break;
530118334Speter	  }
530218334Speter	break;
530318334Speter
530418334Speter      case '\\':
530518334Speter	/* Backslash: treat next character as ordinary.  */
530618334Speter	c = *p++;
530718334Speter
530818334Speter	/* fall through */
530918334Speter      default:
531018334Speter	/* Ordinary character: put it into the current argument.  */
531118334Speter	obstack_1grow (&obstack, c);
531218334Speter	arg_going = 1;
531318334Speter      }
531418334Speter
531590277Sobrien  /* End of string.  */
531690277Sobrien  return 0;
531718334Speter}
531818334Speter
531918334Speter/* Return 0 if we call do_spec_1 and that returns -1.  */
532018334Speter
532152520Sobrienstatic const char *
532218334Speterhandle_braces (p)
532390277Sobrien     const char *p;
532418334Speter{
532552520Sobrien  const char *filter, *body = NULL, *endbody = NULL;
532650599Sobrien  int pipe_p = 0;
532790277Sobrien  int true_once = 0;	/* If, in %{a|b:d}, at least one of a,b was seen.  */
532850599Sobrien  int negate;
532950599Sobrien  int suffix;
533050599Sobrien  int include_blanks = 1;
533190277Sobrien  int elide_switch = 0;
533290277Sobrien  int ordered = 0;
533318334Speter
533450599Sobrien  if (*p == '^')
533590277Sobrien    {
533690277Sobrien      /* A '^' after the open-brace means to not give blanks before args.  */
533790277Sobrien      include_blanks = 0;
533890277Sobrien      ++p;
533990277Sobrien    }
534050599Sobrien
534118334Speter  if (*p == '|')
534290277Sobrien    {
534390277Sobrien      /* A `|' after the open-brace means,
534490277Sobrien	 if the test fails, output a single minus sign rather than nothing.
534590277Sobrien	 This is used in %{|!pipe:...}.  */
534690277Sobrien      pipe_p = 1;
534790277Sobrien      ++p;
534890277Sobrien    }
534918334Speter
535090277Sobrien  if (*p == '<')
535190277Sobrien    {
535290277Sobrien      /* A `<' after the open-brace means that the switch should be
535390277Sobrien	 removed from the command-line.  */
535490277Sobrien      elide_switch = 1;
535590277Sobrien      ++p;
535690277Sobrien    }
535790277Sobrien
535850599Sobriennext_member:
535950599Sobrien  negate = suffix = 0;
536050599Sobrien
536118334Speter  if (*p == '!')
536218334Speter    /* A `!' after the open-brace negates the condition:
536318334Speter       succeed if the specified switch is not present.  */
536418334Speter    negate = 1, ++p;
536518334Speter
536618334Speter  if (*p == '.')
536718334Speter    /* A `.' after the open-brace means test against the current suffix.  */
536818334Speter    {
536950599Sobrien      if (pipe_p)
537018334Speter	abort ();
537118334Speter
537218334Speter      suffix = 1;
537318334Speter      ++p;
537418334Speter    }
537518334Speter
537690277Sobrien  if (elide_switch && (negate || pipe_p || suffix))
537790277Sobrien    {
537890277Sobrien      /* It doesn't make sense to mix elision with other flags.  We
537990277Sobrien	 could fatal() here, but the standard seems to be to abort.  */
538090277Sobrien      abort ();
538190277Sobrien    }
538290277Sobrien
538390277Sobrien next_ampersand:
538418334Speter  filter = p;
538590277Sobrien  while (*p != ':' && *p != '}' && *p != '|' && *p != '&')
538690277Sobrien    p++;
538750599Sobrien
538890277Sobrien  if (*p == '|' && (pipe_p || ordered))
538950599Sobrien    abort ();
539050599Sobrien
539150599Sobrien  if (!body)
539218334Speter    {
539390277Sobrien      if (*p != '}' && *p != '&')
539490277Sobrien	{
539590277Sobrien	  int count = 1;
539690277Sobrien	  const char *q = p;
539750599Sobrien
539890277Sobrien	  while (*q++ != ':')
539990277Sobrien	    continue;
540050599Sobrien	  body = q;
540190277Sobrien
540250599Sobrien	  while (count > 0)
540350599Sobrien	    {
540450599Sobrien	      if (*q == '{')
540590277Sobrien		count++;
540650599Sobrien	      else if (*q == '}')
540790277Sobrien		count--;
540850599Sobrien	      else if (*q == 0)
540990277Sobrien		fatal ("mismatched braces in specs");
541050599Sobrien	      q++;
541150599Sobrien	    }
541250599Sobrien	  endbody = q;
541318334Speter	}
541450599Sobrien      else
541590277Sobrien	body = p, endbody = p + 1;
541618334Speter    }
541718334Speter
541818334Speter  if (suffix)
541918334Speter    {
542018334Speter      int found = (input_suffix != 0
542190277Sobrien		   && (long) strlen (input_suffix) == (long) (p - filter)
542218334Speter		   && strncmp (input_suffix, filter, p - filter) == 0);
542318334Speter
542450599Sobrien      if (body[0] == '}')
542518334Speter	abort ();
542618334Speter
542718334Speter      if (negate != found
542890277Sobrien	  && do_spec_1 (save_string (body, endbody-body-1), 0, NULL) < 0)
542918334Speter	return 0;
543018334Speter    }
543190277Sobrien  else if (p[-1] == '*' && (p[0] == '}' || p[0] == '&'))
543218334Speter    {
543318334Speter      /* Substitute all matching switches as separate args.  */
543490277Sobrien      int i;
543590277Sobrien
543618334Speter      for (i = 0; i < n_switches; i++)
543790277Sobrien	if (!strncmp (switches[i].part1, filter, p - 1 - filter)
543890277Sobrien	    && check_live_switch (i, p - 1 - filter))
543990277Sobrien	  {
544090277Sobrien	    if (elide_switch)
544190277Sobrien	      {
544290277Sobrien		switches[i].live_cond = SWITCH_IGNORE;
544390277Sobrien		switches[i].validated = 1;
544490277Sobrien	      }
544590277Sobrien	    else
544690277Sobrien	      ordered = 1, switches[i].ordering = 1;
544790277Sobrien	  }
544818334Speter    }
544918334Speter  else
545018334Speter    {
545118334Speter      /* Test for presence of the specified switch.  */
545290277Sobrien      int i;
545318334Speter      int present = 0;
545418334Speter
545518334Speter      /* If name specified ends in *, as in {x*:...},
545618334Speter	 check for %* and handle that case.  */
545718334Speter      if (p[-1] == '*' && !negate)
545818334Speter	{
545918334Speter	  int substitution;
546052520Sobrien	  const char *r = body;
546118334Speter
546218334Speter	  /* First see whether we have %*.  */
546318334Speter	  substitution = 0;
546450599Sobrien	  while (r < endbody)
546518334Speter	    {
546618334Speter	      if (*r == '%' && r[1] == '*')
546718334Speter		substitution = 1;
546818334Speter	      r++;
546918334Speter	    }
547018334Speter	  /* If we do, handle that case.  */
547118334Speter	  if (substitution)
547218334Speter	    {
547318334Speter	      /* Substitute all matching switches as separate args.
547418334Speter		 But do this by substituting for %*
547518334Speter		 in the text that follows the colon.  */
547618334Speter
547718334Speter	      unsigned hard_match_len = p - filter - 1;
547850599Sobrien	      char *string = save_string (body, endbody - body - 1);
547918334Speter
548018334Speter	      for (i = 0; i < n_switches; i++)
548118334Speter		if (!strncmp (switches[i].part1, filter, hard_match_len)
548218334Speter		    && check_live_switch (i, -1))
548318334Speter		  {
548418334Speter		    do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
548518334Speter		    /* Pass any arguments this switch has.  */
548650599Sobrien		    give_switch (i, 1, 1);
548790277Sobrien		    suffix_subst = NULL;
548818334Speter		  }
548918334Speter
549050599Sobrien	      /* We didn't match.  Try again.  */
549150599Sobrien	      if (*p++ == '|')
549250599Sobrien		goto next_member;
549350599Sobrien	      return endbody;
549418334Speter	    }
549518334Speter	}
549618334Speter
549718334Speter      /* If name specified ends in *, as in {x*:...},
549818334Speter	 check for presence of any switch name starting with x.  */
549918334Speter      if (p[-1] == '*')
550018334Speter	{
550118334Speter	  for (i = 0; i < n_switches; i++)
550218334Speter	    {
550318334Speter	      unsigned hard_match_len = p - filter - 1;
550418334Speter
550518334Speter	      if (!strncmp (switches[i].part1, filter, hard_match_len)
550618334Speter		  && check_live_switch (i, hard_match_len))
550718334Speter		{
550818334Speter		  present = 1;
550990277Sobrien		  break;
551018334Speter		}
551118334Speter	    }
551218334Speter	}
551318334Speter      /* Otherwise, check for presence of exact name specified.  */
551418334Speter      else
551518334Speter	{
551618334Speter	  for (i = 0; i < n_switches; i++)
551718334Speter	    {
551818334Speter	      if (!strncmp (switches[i].part1, filter, p - filter)
551918334Speter		  && switches[i].part1[p - filter] == 0
552018334Speter		  && check_live_switch (i, -1))
552118334Speter		{
552218334Speter		  present = 1;
552318334Speter		  break;
552418334Speter		}
552518334Speter	    }
552618334Speter	}
552718334Speter
552850599Sobrien      /* If it is as desired (present for %{s...}, absent for %{!s...})
552918334Speter	 then substitute either the switch or the specified
553018334Speter	 conditional text.  */
553118334Speter      if (present != negate)
553218334Speter	{
553390277Sobrien	  if (elide_switch)
553418334Speter	    {
553590277Sobrien	      switches[i].live_cond = SWITCH_IGNORE;
553690277Sobrien	      switches[i].validated = 1;
553718334Speter	    }
553890277Sobrien	  else if (ordered || *p == '&')
553990277Sobrien	    ordered = 1, switches[i].ordering = 1;
554090277Sobrien	  else if (*p == '}')
554190277Sobrien	    give_switch (i, 0, include_blanks);
554218334Speter	  else
554390277Sobrien	    /* Even if many alternatives are matched, only output once.  */
554490277Sobrien	    true_once = 1;
554518334Speter	}
554650599Sobrien      else if (pipe_p)
554718334Speter	{
554818334Speter	  /* Here if a %{|...} conditional fails: output a minus sign,
554918334Speter	     which means "standard output" or "standard input".  */
555090277Sobrien	  do_spec_1 ("-", 0, NULL);
555150599Sobrien	  return endbody;
555218334Speter	}
555318334Speter    }
555418334Speter
555550599Sobrien  /* We didn't match; try again.  */
555650599Sobrien  if (*p++ == '|')
555750599Sobrien    goto next_member;
555850599Sobrien
555990277Sobrien  if (p[-1] == '&')
556090277Sobrien    {
556190277Sobrien      body = 0;
556290277Sobrien      goto next_ampersand;
556390277Sobrien    }
556490277Sobrien
556590277Sobrien  if (ordered)
556690277Sobrien    {
556790277Sobrien      int i;
556890277Sobrien      /* Doing this set of switches later preserves their command-line
556990277Sobrien	 ordering.  This is needed for e.g. -U, -D and -A.  */
557090277Sobrien      for (i = 0; i < n_switches; i++)
557190277Sobrien	if (switches[i].ordering == 1)
557290277Sobrien	  {
557390277Sobrien	    switches[i].ordering = 0;
557490277Sobrien	    give_switch (i, 0, include_blanks);
557590277Sobrien	  }
557690277Sobrien    }
557790277Sobrien  /* Process the spec just once, regardless of match count.  */
557890277Sobrien  else if (true_once)
557990277Sobrien    {
558090277Sobrien      if (do_spec_1 (save_string (body, endbody - body - 1),
558190277Sobrien		     0, NULL) < 0)
558290277Sobrien	return 0;
558390277Sobrien    }
558490277Sobrien
558550599Sobrien  return endbody;
558618334Speter}
558718334Speter
558818334Speter/* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
558918334Speter   on the command line.  PREFIX_LENGTH is the length of XXX in an {XXX*}
559018334Speter   spec, or -1 if either exact match or %* is used.
559118334Speter
559218334Speter   A -O switch is obsoleted by a later -O switch.  A -f, -m, or -W switch
559318334Speter   whose value does not begin with "no-" is obsoleted by the same value
559418334Speter   with the "no-", similarly for a switch with the "no-" prefix.  */
559518334Speter
559618334Speterstatic int
559718334Spetercheck_live_switch (switchnum, prefix_length)
559818334Speter     int switchnum;
559918334Speter     int prefix_length;
560018334Speter{
560152520Sobrien  const char *name = switches[switchnum].part1;
560218334Speter  int i;
560318334Speter
560418334Speter  /* In the common case of {<at-most-one-letter>*}, a negating
560518334Speter     switch would always match, so ignore that case.  We will just
560618334Speter     send the conflicting switches to the compiler phase.  */
560718334Speter  if (prefix_length >= 0 && prefix_length <= 1)
560818334Speter    return 1;
560918334Speter
561018334Speter  /* If we already processed this switch and determined if it was
561118334Speter     live or not, return our past determination.  */
561218334Speter  if (switches[switchnum].live_cond != 0)
561318334Speter    return switches[switchnum].live_cond > 0;
561418334Speter
561518334Speter  /* Now search for duplicate in a manner that depends on the name.  */
561618334Speter  switch (*name)
561718334Speter    {
561818334Speter    case 'O':
561990277Sobrien      for (i = switchnum + 1; i < n_switches; i++)
562090277Sobrien	if (switches[i].part1[0] == 'O')
562190277Sobrien	  {
562290277Sobrien	    switches[switchnum].validated = 1;
562390277Sobrien	    switches[switchnum].live_cond = SWITCH_FALSE;
562490277Sobrien	    return 0;
562590277Sobrien	  }
562618334Speter      break;
562718334Speter
562818334Speter    case 'W':  case 'f':  case 'm':
562918334Speter      if (! strncmp (name + 1, "no-", 3))
563018334Speter	{
563150599Sobrien	  /* We have Xno-YYY, search for XYYY.  */
563218334Speter	  for (i = switchnum + 1; i < n_switches; i++)
563318334Speter	    if (switches[i].part1[0] == name[0]
563418334Speter		&& ! strcmp (&switches[i].part1[1], &name[4]))
563590277Sobrien	      {
563690277Sobrien		switches[switchnum].validated = 1;
563790277Sobrien		switches[switchnum].live_cond = SWITCH_FALSE;
563890277Sobrien		return 0;
563990277Sobrien	      }
564018334Speter	}
564118334Speter      else
564218334Speter	{
564318334Speter	  /* We have XYYY, search for Xno-YYY.  */
564418334Speter	  for (i = switchnum + 1; i < n_switches; i++)
564518334Speter	    if (switches[i].part1[0] == name[0]
564618334Speter		&& switches[i].part1[1] == 'n'
564718334Speter		&& switches[i].part1[2] == 'o'
564818334Speter		&& switches[i].part1[3] == '-'
564918334Speter		&& !strcmp (&switches[i].part1[4], &name[1]))
565090277Sobrien	      {
565190277Sobrien		switches[switchnum].validated = 1;
565290277Sobrien		switches[switchnum].live_cond = SWITCH_FALSE;
565390277Sobrien		return 0;
565490277Sobrien	      }
565518334Speter	}
565618334Speter      break;
565718334Speter    }
565818334Speter
565918334Speter  /* Otherwise the switch is live.  */
566090277Sobrien  switches[switchnum].live_cond = SWITCH_LIVE;
566118334Speter  return 1;
566218334Speter}
566318334Speter
566418334Speter/* Pass a switch to the current accumulating command
566518334Speter   in the same form that we received it.
566618334Speter   SWITCHNUM identifies the switch; it is an index into
566718334Speter   the vector of switches gcc received, which is `switches'.
566818334Speter   This cannot fail since it never finishes a command line.
566918334Speter
567050599Sobrien   If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.
567118334Speter
567250599Sobrien   If INCLUDE_BLANKS is nonzero, then we include blanks before each argument
567350599Sobrien   of the switch.  */
567450599Sobrien
567518334Speterstatic void
567650599Sobriengive_switch (switchnum, omit_first_word, include_blanks)
567718334Speter     int switchnum;
567818334Speter     int omit_first_word;
567950599Sobrien     int include_blanks;
568018334Speter{
568190277Sobrien  if (switches[switchnum].live_cond == SWITCH_IGNORE)
568290277Sobrien    return;
568390277Sobrien
568418334Speter  if (!omit_first_word)
568518334Speter    {
568690277Sobrien      do_spec_1 ("-", 0, NULL);
568790277Sobrien      do_spec_1 (switches[switchnum].part1, 1, NULL);
568818334Speter    }
568950599Sobrien
569018334Speter  if (switches[switchnum].args != 0)
569118334Speter    {
569290277Sobrien      const char **p;
569318334Speter      for (p = switches[switchnum].args; *p; p++)
569418334Speter	{
569590277Sobrien	  const char *arg = *p;
569690277Sobrien
569750599Sobrien	  if (include_blanks)
569890277Sobrien	    do_spec_1 (" ", 0, NULL);
569990277Sobrien	  if (suffix_subst)
570090277Sobrien	    {
570190277Sobrien	      unsigned length = strlen (arg);
570290277Sobrien	      int dot = 0;
570390277Sobrien
570490277Sobrien	      while (length-- && !IS_DIR_SEPARATOR (arg[length]))
570590277Sobrien		if (arg[length] == '.')
570690277Sobrien		  {
570790277Sobrien		    ((char *)arg)[length] = 0;
570890277Sobrien		    dot = 1;
570990277Sobrien		    break;
571090277Sobrien		  }
571190277Sobrien	      do_spec_1 (arg, 1, NULL);
571290277Sobrien	      if (dot)
571390277Sobrien		((char *)arg)[length] = '.';
571490277Sobrien	      do_spec_1 (suffix_subst, 1, NULL);
571590277Sobrien	    }
571690277Sobrien	  else
571790277Sobrien	    do_spec_1 (arg, 1, NULL);
571818334Speter	}
571918334Speter    }
572050599Sobrien
572190277Sobrien  do_spec_1 (" ", 0, NULL);
572252520Sobrien  switches[switchnum].validated = 1;
572318334Speter}
572418334Speter
572518334Speter/* Search for a file named NAME trying various prefixes including the
572618334Speter   user's -B prefix and some standard ones.
572718334Speter   Return the absolute file name found.  If nothing is found, return NAME.  */
572818334Speter
572952520Sobrienstatic const char *
573018334Speterfind_file (name)
573152520Sobrien     const char *name;
573218334Speter{
573318334Speter  char *newname;
573418334Speter
573518334Speter  /* Try multilib_dir if it is defined.  */
573618334Speter  if (multilib_dir != NULL)
573718334Speter    {
573890277Sobrien      const char *const try = ACONCAT ((multilib_dir, dir_separator_str, name, NULL));
573918334Speter
574018334Speter      newname = find_a_file (&startfile_prefixes, try, R_OK);
574118334Speter
574218334Speter      /* If we don't find it in the multi library dir, then fall
574318334Speter	 through and look for it in the normal places.  */
574418334Speter      if (newname != NULL)
574518334Speter	return newname;
574618334Speter    }
574718334Speter
574818334Speter  newname = find_a_file (&startfile_prefixes, name, R_OK);
574918334Speter  return newname ? newname : name;
575018334Speter}
575118334Speter
575218334Speter/* Determine whether a directory exists.  If LINKER, return 0 for
575318334Speter   certain fixed names not needed by the linker.  If not LINKER, it is
575418334Speter   only important to return 0 if the host machine has a small ARG_MAX
575518334Speter   limit.  */
575618334Speter
575718334Speterstatic int
575818334Speteris_directory (path1, path2, linker)
575952520Sobrien     const char *path1;
576052520Sobrien     const char *path2;
576118334Speter     int linker;
576218334Speter{
576318334Speter  int len1 = strlen (path1);
576418334Speter  int len2 = strlen (path2);
576518334Speter  char *path = (char *) alloca (3 + len1 + len2);
576618334Speter  char *cp;
576718334Speter  struct stat st;
576818334Speter
576918334Speter#ifndef SMALL_ARG_MAX
577018334Speter  if (! linker)
577118334Speter    return 1;
577218334Speter#endif
577318334Speter
577418334Speter  /* Construct the path from the two parts.  Ensure the string ends with "/.".
577518334Speter     The resulting path will be a directory even if the given path is a
577618334Speter     symbolic link.  */
577752520Sobrien  memcpy (path, path1, len1);
577852520Sobrien  memcpy (path + len1, path2, len2);
577918334Speter  cp = path + len1 + len2;
578052520Sobrien  if (!IS_DIR_SEPARATOR (cp[-1]))
578118334Speter    *cp++ = DIR_SEPARATOR;
578218334Speter  *cp++ = '.';
578318334Speter  *cp = '\0';
578418334Speter
578551232Sbde#ifndef FREEBSD_NATIVE
578618334Speter  /* Exclude directories that the linker is known to search.  */
578718334Speter  if (linker
578818334Speter      && ((cp - path == 6
578990277Sobrien	   && strcmp (path, concat (dir_separator_str, "lib",
579090277Sobrien				    dir_separator_str, ".", NULL)) == 0)
579118334Speter	  || (cp - path == 10
579290277Sobrien	      && strcmp (path, concat (dir_separator_str, "usr",
579390277Sobrien				       dir_separator_str, "lib",
579490277Sobrien				       dir_separator_str, ".", NULL)) == 0)))
579518334Speter    return 0;
579651232Sbde#endif /* FREEBSD_NATIVE */
579718334Speter
579818334Speter  return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
579918334Speter}
580090277Sobrien
580190277Sobrien/* Set up the various global variables to indicate that we're processing
580290277Sobrien   the input file named FILENAME.  */
580390277Sobrien
580490277Sobrienvoid
580590277Sobrienset_input (filename)
580690277Sobrien     const char *filename;
580790277Sobrien{
580890277Sobrien  const char *p;
580990277Sobrien
581090277Sobrien  input_filename = filename;
581190277Sobrien  input_filename_length = strlen (input_filename);
581290277Sobrien
581390277Sobrien  input_basename = input_filename;
581490277Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
581590277Sobrien  /* Skip drive name so 'x:foo' is handled properly.  */
581690277Sobrien  if (input_basename[1] == ':')
581790277Sobrien    input_basename += 2;
581890277Sobrien#endif
581990277Sobrien  for (p = input_basename; *p; p++)
582090277Sobrien    if (IS_DIR_SEPARATOR (*p))
582190277Sobrien      input_basename = p + 1;
582290277Sobrien
582390277Sobrien  /* Find a suffix starting with the last period,
582490277Sobrien     and set basename_length to exclude that suffix.  */
582590277Sobrien  basename_length = strlen (input_basename);
582690277Sobrien  suffixed_basename_length = basename_length;
582790277Sobrien  p = input_basename + basename_length;
582890277Sobrien  while (p != input_basename && *p != '.')
582990277Sobrien    --p;
583090277Sobrien  if (*p == '.' && p != input_basename)
583190277Sobrien    {
583290277Sobrien      basename_length = p - input_basename;
583390277Sobrien      input_suffix = p + 1;
583490277Sobrien    }
583590277Sobrien  else
583690277Sobrien    input_suffix = "";
583790277Sobrien
583890277Sobrien  /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then
583990277Sobrien     we will need to do a stat on the input_filename.  The
584090277Sobrien     INPUT_STAT_SET signals that the stat is needed.  */
584190277Sobrien  input_stat_set = 0;
584290277Sobrien}
584318334Speter
584418334Speter/* On fatal signals, delete all the temporary files.  */
584518334Speter
584618334Speterstatic void
584718334Speterfatal_error (signum)
584818334Speter     int signum;
584918334Speter{
585018334Speter  signal (signum, SIG_DFL);
585118334Speter  delete_failure_queue ();
585218334Speter  delete_temp_files ();
585318334Speter  /* Get the same signal again, this time not handled,
585418334Speter     so its normal effect occurs.  */
585518334Speter  kill (getpid (), signum);
585618334Speter}
585718334Speter
585890277Sobrienextern int main PARAMS ((int, const char *const *));
585990277Sobrien
586018334Speterint
586118334Spetermain (argc, argv)
586218334Speter     int argc;
586390277Sobrien     const char *const *argv;
586418334Speter{
586590277Sobrien  size_t i;
586618334Speter  int value;
586718334Speter  int linker_was_run = 0;
586818334Speter  char *explicit_link_files;
586918334Speter  char *specs_file;
587052520Sobrien  const char *p;
587150599Sobrien  struct user_specs *uptr;
587218334Speter
587318334Speter  p = argv[0] + strlen (argv[0]);
587452520Sobrien  while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
587552520Sobrien    --p;
587618334Speter  programname = p;
587718334Speter
587890277Sobrien  xmalloc_set_program_name (programname);
587990277Sobrien
588090277Sobrien#ifdef GCC_DRIVER_HOST_INITIALIZATION
588190277Sobrien  /* Perform host dependent initialization when needed.  */
588290277Sobrien  GCC_DRIVER_HOST_INITIALIZATION;
588352520Sobrien#endif
588452520Sobrien
588590277Sobrien  gcc_init_libintl ();
588690277Sobrien
588718334Speter  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
588818334Speter    signal (SIGINT, fatal_error);
588918334Speter#ifdef SIGHUP
589018334Speter  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
589118334Speter    signal (SIGHUP, fatal_error);
589218334Speter#endif
589318334Speter  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
589418334Speter    signal (SIGTERM, fatal_error);
589518334Speter#ifdef SIGPIPE
589618334Speter  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
589718334Speter    signal (SIGPIPE, fatal_error);
589818334Speter#endif
589990277Sobrien#ifdef SIGCHLD
590090277Sobrien  /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
590190277Sobrien     receive the signal.  A different setting is inheritable */
590290277Sobrien  signal (SIGCHLD, SIG_DFL);
590390277Sobrien#endif
590418334Speter
590518334Speter  argbuf_length = 10;
590690277Sobrien  argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *));
590718334Speter
590818334Speter  obstack_init (&obstack);
590918334Speter
591050599Sobrien  /* Build multilib_select, et. al from the separate lines that make up each
591150599Sobrien     multilib selection.  */
591250599Sobrien  {
591390277Sobrien    const char *const *q = multilib_raw;
591450599Sobrien    int need_space;
591550599Sobrien
591650599Sobrien    obstack_init (&multilib_obstack);
591750599Sobrien    while ((p = *q++) != (char *) 0)
591850599Sobrien      obstack_grow (&multilib_obstack, p, strlen (p));
591950599Sobrien
592050599Sobrien    obstack_1grow (&multilib_obstack, 0);
592150599Sobrien    multilib_select = obstack_finish (&multilib_obstack);
592250599Sobrien
592350599Sobrien    q = multilib_matches_raw;
592450599Sobrien    while ((p = *q++) != (char *) 0)
592550599Sobrien      obstack_grow (&multilib_obstack, p, strlen (p));
592650599Sobrien
592750599Sobrien    obstack_1grow (&multilib_obstack, 0);
592850599Sobrien    multilib_matches = obstack_finish (&multilib_obstack);
592950599Sobrien
593090277Sobrien    q = multilib_exclusions_raw;
593190277Sobrien    while ((p = *q++) != (char *) 0)
593290277Sobrien      obstack_grow (&multilib_obstack, p, strlen (p));
593390277Sobrien
593490277Sobrien    obstack_1grow (&multilib_obstack, 0);
593590277Sobrien    multilib_exclusions = obstack_finish (&multilib_obstack);
593690277Sobrien
593750599Sobrien    need_space = FALSE;
593890277Sobrien    for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
593950599Sobrien      {
594050599Sobrien	if (need_space)
594150599Sobrien	  obstack_1grow (&multilib_obstack, ' ');
594250599Sobrien	obstack_grow (&multilib_obstack,
594350599Sobrien		      multilib_defaults_raw[i],
594450599Sobrien		      strlen (multilib_defaults_raw[i]));
594550599Sobrien	need_space = TRUE;
594650599Sobrien      }
594750599Sobrien
594850599Sobrien    obstack_1grow (&multilib_obstack, 0);
594950599Sobrien    multilib_defaults = obstack_finish (&multilib_obstack);
595050599Sobrien  }
595150599Sobrien
595218334Speter  /* Set up to remember the pathname of gcc and any options
595318334Speter     needed for collect.  We use argv[0] instead of programname because
595418334Speter     we need the complete pathname.  */
595518334Speter  obstack_init (&collect_obstack);
595690277Sobrien  obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
595790277Sobrien  obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
595818334Speter  putenv (obstack_finish (&collect_obstack));
595918334Speter
596018334Speter#ifdef INIT_ENVIRONMENT
596118334Speter  /* Set up any other necessary machine specific environment variables.  */
596218334Speter  putenv (INIT_ENVIRONMENT);
596318334Speter#endif
596418334Speter
596518334Speter  /* Make a table of what switches there are (switches, n_switches).
596618334Speter     Make a table of specified input files (infiles, n_infiles).
596718334Speter     Decode switches that are handled locally.  */
596818334Speter
596918334Speter  process_command (argc, argv);
597018334Speter
597118334Speter  /* Initialize the vector of specs to just the default.
597218334Speter     This means one element containing 0s, as a terminator.  */
597318334Speter
597418334Speter  compilers = (struct compiler *) xmalloc (sizeof default_compilers);
597590277Sobrien  memcpy ((char *) compilers, (char *) default_compilers,
597690277Sobrien	  sizeof default_compilers);
597718334Speter  n_compilers = n_default_compilers;
597818334Speter
597918334Speter  /* Read specs from a file if there is one.  */
598018334Speter
598118346Speter#ifndef FREEBSD_NATIVE
598250599Sobrien  machine_suffix = concat (spec_machine, dir_separator_str,
598390277Sobrien			   spec_version, dir_separator_str, NULL);
598490277Sobrien  just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
598550599Sobrien#else /* FREEBSD_NATIVE */
598650599Sobrien  just_machine_suffix = "";
598750599Sobrien#endif /* FREEBSD_NATIVE */
598818334Speter
598918334Speter  specs_file = find_a_file (&startfile_prefixes, "specs", R_OK);
599018334Speter  /* Read the specs file unless it is a default one.  */
599118334Speter  if (specs_file != 0 && strcmp (specs_file, "specs"))
599250599Sobrien    read_specs (specs_file, TRUE);
599350599Sobrien  else
599450599Sobrien    init_spec ();
599518334Speter
599650599Sobrien  /* We need to check standard_exec_prefix/just_machine_suffix/specs
599790277Sobrien     for any override of as, ld and libraries.  */
599850599Sobrien  specs_file = (char *) alloca (strlen (standard_exec_prefix)
599950599Sobrien				+ strlen (just_machine_suffix)
600050599Sobrien				+ sizeof ("specs"));
600150599Sobrien
600250599Sobrien  strcpy (specs_file, standard_exec_prefix);
600350599Sobrien  strcat (specs_file, just_machine_suffix);
600450599Sobrien  strcat (specs_file, "specs");
600550599Sobrien  if (access (specs_file, R_OK) == 0)
600650599Sobrien    read_specs (specs_file, TRUE);
600790277Sobrien
600818334Speter  /* If not cross-compiling, look for startfiles in the standard places.  */
600950599Sobrien  if (*cross_compile == '0')
601018334Speter    {
601190277Sobrien      if (*md_exec_prefix)
601290277Sobrien	{
601390277Sobrien	  add_prefix (&exec_prefixes, md_exec_prefix, "GCC",
601490277Sobrien		      PREFIX_PRIORITY_LAST, 0, NULL);
601590277Sobrien	  add_prefix (&startfile_prefixes, md_exec_prefix, "GCC",
601690277Sobrien		      PREFIX_PRIORITY_LAST, 0, NULL);
601790277Sobrien	}
601818334Speter
601990277Sobrien      if (*md_startfile_prefix)
602090277Sobrien	add_prefix (&startfile_prefixes, md_startfile_prefix, "GCC",
602190277Sobrien		    PREFIX_PRIORITY_LAST, 0, NULL);
602218334Speter
602390277Sobrien      if (*md_startfile_prefix_1)
602490277Sobrien	add_prefix (&startfile_prefixes, md_startfile_prefix_1, "GCC",
602590277Sobrien		    PREFIX_PRIORITY_LAST, 0, NULL);
602618334Speter
602718334Speter      /* If standard_startfile_prefix is relative, base it on
602818334Speter	 standard_exec_prefix.  This lets us move the installed tree
602918334Speter	 as a unit.  If GCC_EXEC_PREFIX is defined, base
603018334Speter	 standard_startfile_prefix on that as well.  */
603190277Sobrien      if (IS_ABSOLUTE_PATHNAME (standard_startfile_prefix))
603250599Sobrien	add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
603390277Sobrien		    PREFIX_PRIORITY_LAST, 0, NULL);
603418334Speter      else
603518334Speter	{
603618334Speter	  if (gcc_exec_prefix)
603718334Speter	    add_prefix (&startfile_prefixes,
603850599Sobrien			concat (gcc_exec_prefix, machine_suffix,
603990277Sobrien				standard_startfile_prefix, NULL),
604090277Sobrien			NULL, PREFIX_PRIORITY_LAST, 0, NULL);
604118334Speter	  add_prefix (&startfile_prefixes,
604250599Sobrien		      concat (standard_exec_prefix,
604350599Sobrien			      machine_suffix,
604490277Sobrien			      standard_startfile_prefix, NULL),
604590277Sobrien		      NULL, PREFIX_PRIORITY_LAST, 0, NULL);
604690277Sobrien	}
604718334Speter
604818346Speter#ifndef FREEBSD_NATIVE
604950599Sobrien      add_prefix (&startfile_prefixes, standard_startfile_prefix_1,
605090277Sobrien		  "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL);
605150599Sobrien      add_prefix (&startfile_prefixes, standard_startfile_prefix_2,
605290277Sobrien		  "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL);
605318334Speter#if 0 /* Can cause surprises, and one can use -B./ instead.  */
605490277Sobrien      add_prefix (&startfile_prefixes, "./", NULL,
605590277Sobrien		  PREFIX_PRIORITY_LAST, 1, NULL);
605618334Speter#endif
605718346Speter#endif /* FREEBSD_NATIVE */
605818334Speter    }
605918334Speter  else
606018334Speter    {
606190277Sobrien      if (!IS_ABSOLUTE_PATHNAME (standard_startfile_prefix)
606290277Sobrien	  && gcc_exec_prefix)
606318334Speter	add_prefix (&startfile_prefixes,
606450599Sobrien		    concat (gcc_exec_prefix, machine_suffix,
606590277Sobrien			    standard_startfile_prefix, NULL),
606690277Sobrien		    "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL);
606718334Speter    }
606818334Speter
606952520Sobrien  /* Process any user specified specs in the order given on the command
607052520Sobrien     line.  */
607152520Sobrien  for (uptr = user_specs_head; uptr; uptr = uptr->next)
607252520Sobrien    {
607352520Sobrien      char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK);
607452520Sobrien      read_specs (filename ? filename : uptr->filename, FALSE);
607552520Sobrien    }
607652520Sobrien
607718334Speter  /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
607818334Speter  if (gcc_exec_prefix)
607990277Sobrien    gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
608090277Sobrien			      spec_version, dir_separator_str, NULL);
608118334Speter
608218334Speter  /* Now we have the specs.
608318334Speter     Set the `valid' bits for switches that match anything in any spec.  */
608418334Speter
608518334Speter  validate_all_switches ();
608618334Speter
608718334Speter  /* Now that we have the switches and the specs, set
608818334Speter     the subdirectory based on the options.  */
608918334Speter  set_multilib_dir ();
609018334Speter
609118334Speter  /* Warn about any switches that no pass was interested in.  */
609218334Speter
609390277Sobrien  for (i = 0; (int) i < n_switches; i++)
609452520Sobrien    if (! switches[i].validated)
609518334Speter      error ("unrecognized option `-%s'", switches[i].part1);
609618334Speter
609718334Speter  /* Obey some of the options.  */
609818334Speter
609918334Speter  if (print_search_dirs)
610018334Speter    {
610190277Sobrien      printf (_("install: %s%s\n"), standard_exec_prefix, machine_suffix);
610290277Sobrien      printf (_("programs: %s\n"), build_search_list (&exec_prefixes, "", 0));
610390277Sobrien      printf (_("libraries: %s\n"), build_search_list (&startfile_prefixes, "", 0));
610490277Sobrien      return (0);
610518334Speter    }
610618334Speter
610718334Speter  if (print_file_name)
610818334Speter    {
610918334Speter      printf ("%s\n", find_file (print_file_name));
611090277Sobrien      return (0);
611118334Speter    }
611218334Speter
611318334Speter  if (print_prog_name)
611418334Speter    {
611518334Speter      char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK);
611618334Speter      printf ("%s\n", (newname ? newname : print_prog_name));
611790277Sobrien      return (0);
611818334Speter    }
611918334Speter
612018334Speter  if (print_multi_lib)
612118334Speter    {
612218334Speter      print_multilib_info ();
612390277Sobrien      return (0);
612418334Speter    }
612518334Speter
612618334Speter  if (print_multi_directory)
612718334Speter    {
612818334Speter      if (multilib_dir == NULL)
612918334Speter	printf (".\n");
613018334Speter      else
613118334Speter	printf ("%s\n", multilib_dir);
613290277Sobrien      return (0);
613318334Speter    }
613418334Speter
613590277Sobrien  if (target_help_flag)
613690277Sobrien   {
613790277Sobrien      /* Print if any target specific options.  */
613890277Sobrien
613990277Sobrien      /* We do not exit here. Instead we have created a fake input file
614090277Sobrien         called 'target-dummy' which needs to be compiled, and we pass this
614190277Sobrien         on to the various sub-processes, along with the --target-help
614290277Sobrien         switch.  */
614390277Sobrien    }
614490277Sobrien
614550599Sobrien  if (print_help_list)
614650599Sobrien    {
614750599Sobrien      display_help ();
614850599Sobrien
614950599Sobrien      if (! verbose_flag)
615050599Sobrien	{
615190277Sobrien	  printf (_("\nFor bug reporting instructions, please see:\n"));
615257849Sobrien	  printf ("%s.\n", GCCBUGURL);
615390277Sobrien
615490277Sobrien	  return (0);
615550599Sobrien	}
615650599Sobrien
615750599Sobrien      /* We do not exit here.  Instead we have created a fake input file
615850599Sobrien	 called 'help-dummy' which needs to be compiled, and we pass this
615990277Sobrien	 on the various sub-processes, along with the --help switch.  */
616050599Sobrien    }
616190277Sobrien
616218334Speter  if (verbose_flag)
616318334Speter    {
616450599Sobrien      int n;
616590277Sobrien      const char *thrmod;
616650599Sobrien
616790277Sobrien      notice ("Configured with: %s\n", configuration_arguments);
616890277Sobrien
616990277Sobrien#ifdef THREAD_MODEL_SPEC
617090277Sobrien      /* We could have defined THREAD_MODEL_SPEC to "%*" by default,
617190277Sobrien	 but there's no point in doing all this processing just to get
617290277Sobrien	 thread_model back.  */
617390277Sobrien      obstack_init (&obstack);
617490277Sobrien      do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
617590277Sobrien      obstack_1grow (&obstack, '\0');
617690277Sobrien      thrmod = obstack_finish (&obstack);
617790277Sobrien#else
617890277Sobrien      thrmod = thread_model;
617990277Sobrien#endif
618090277Sobrien
618190277Sobrien      notice ("Thread model: %s\n", thrmod);
618290277Sobrien
618350599Sobrien      /* compiler_version is truncated at the first space when initialized
618450599Sobrien	 from version string, so truncate version_string at the first space
618550599Sobrien	 before comparing.  */
618650599Sobrien      for (n = 0; version_string[n]; n++)
618750599Sobrien	if (version_string[n] == ' ')
618850599Sobrien	  break;
618950599Sobrien
619050599Sobrien      if (! strncmp (version_string, compiler_version, n)
619150599Sobrien	  && compiler_version[n] == 0)
619252520Sobrien	notice ("gcc version %s\n", version_string);
619318334Speter      else
619452520Sobrien	notice ("gcc driver version %s executing gcc version %s\n",
619552520Sobrien		version_string, compiler_version);
619618334Speter
619718334Speter      if (n_infiles == 0)
619890277Sobrien	return (0);
619918334Speter    }
620018334Speter
620150599Sobrien  if (n_infiles == added_libraries)
620218346Speter    fatal ("No input files specified");
620318334Speter
620418334Speter  /* Make a place to record the compiler output file names
620518334Speter     that correspond to the input files.  */
620618334Speter
620750599Sobrien  i = n_infiles;
620850599Sobrien  i += lang_specific_extra_outfiles;
620990277Sobrien  outfiles = (const char **) xcalloc (i, sizeof (char *));
621018334Speter
621118334Speter  /* Record which files were specified explicitly as link input.  */
621218334Speter
621390277Sobrien  explicit_link_files = xcalloc (1, n_infiles);
621418334Speter
621590277Sobrien  for (i = 0; (int) i < n_infiles; i++)
621618334Speter    {
621718334Speter      int this_file_error = 0;
621818334Speter
621918334Speter      /* Tell do_spec what to substitute for %i.  */
622018334Speter
622118334Speter      input_file_number = i;
622290277Sobrien      set_input (infiles[i].name);
622318334Speter
622418334Speter      /* Use the same thing in %o, unless cp->spec says otherwise.  */
622518334Speter
622618334Speter      outfiles[i] = input_filename;
622718334Speter
622818334Speter      /* Figure out which compiler from the file's suffix.  */
622918334Speter
623090277Sobrien      input_file_compiler
623190277Sobrien	= lookup_compiler (infiles[i].name, input_filename_length,
623290277Sobrien			   infiles[i].language);
623390277Sobrien
623490277Sobrien      if (input_file_compiler)
623518334Speter	{
623618334Speter	  /* Ok, we found an applicable compiler.  Run its spec.  */
623718334Speter
623890277Sobrien	  if (input_file_compiler->spec[0] == '#')
623918334Speter	    {
624090277Sobrien	      error ("%s: %s compiler not installed on this system",
624190277Sobrien		     input_filename, &input_file_compiler->spec[1]);
624290277Sobrien	      this_file_error = 1;
624318334Speter	    }
624418334Speter	  else
624590277Sobrien	    {
624690277Sobrien	      value = do_spec (input_file_compiler->spec);
624790277Sobrien	      if (value < 0)
624890277Sobrien		this_file_error = 1;
624990277Sobrien	    }
625018334Speter	}
625118334Speter
625218334Speter      /* If this file's name does not contain a recognized suffix,
625318334Speter	 record it as explicit linker input.  */
625418334Speter
625518334Speter      else
625618334Speter	explicit_link_files[i] = 1;
625718334Speter
625818334Speter      /* Clear the delete-on-failure queue, deleting the files in it
625918334Speter	 if this compilation failed.  */
626018334Speter
626118334Speter      if (this_file_error)
626218334Speter	{
626318334Speter	  delete_failure_queue ();
626418334Speter	  error_count++;
626518334Speter	}
626618334Speter      /* If this compilation succeeded, don't delete those files later.  */
626718334Speter      clear_failure_queue ();
626818334Speter    }
626918334Speter
627090277Sobrien  /* Reset the output file name to the first input file name, for use
627190277Sobrien     with %b in LINK_SPEC on a target that prefers not to emit a.out
627290277Sobrien     by default.  */
627390277Sobrien  if (n_infiles > 0)
627490277Sobrien    set_input (infiles[0].name);
627590277Sobrien
627652520Sobrien  if (error_count == 0)
627752520Sobrien    {
627852520Sobrien      /* Make sure INPUT_FILE_NUMBER points to first available open
627952520Sobrien	 slot.  */
628052520Sobrien      input_file_number = n_infiles;
628152520Sobrien      if (lang_specific_pre_link ())
628252520Sobrien	error_count++;
628352520Sobrien    }
628450599Sobrien
628518334Speter  /* Run ld to link all the compiler output files.  */
628618334Speter
628718334Speter  if (error_count == 0)
628818334Speter    {
628918334Speter      int tmp = execution_count;
629018334Speter
629190277Sobrien      /* We'll use ld if we can't find collect2.  */
629250599Sobrien      if (! strcmp (linker_name_spec, "collect2"))
629350599Sobrien	{
629450599Sobrien	  char *s = find_a_file (&exec_prefixes, "collect2", X_OK);
629550599Sobrien	  if (s == NULL)
629650599Sobrien	    linker_name_spec = "ld";
629750599Sobrien	}
629818334Speter      /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
629918334Speter	 for collect.  */
630090277Sobrien      putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH");
630190277Sobrien      putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV);
630218334Speter
630318334Speter      value = do_spec (link_command_spec);
630418334Speter      if (value < 0)
630518334Speter	error_count = 1;
630618334Speter      linker_was_run = (tmp != execution_count);
630718334Speter    }
630818334Speter
630918334Speter  /* If options said don't run linker,
631018334Speter     complain about input files to be given to the linker.  */
631118334Speter
631218334Speter  if (! linker_was_run && error_count == 0)
631390277Sobrien    for (i = 0; (int) i < n_infiles; i++)
631418334Speter      if (explicit_link_files[i])
631590277Sobrien	error ("%s: linker input file unused because linking not done",
631618334Speter	       outfiles[i]);
631718334Speter
631818334Speter  /* Delete some or all of the temporary files we made.  */
631918334Speter
632018334Speter  if (error_count)
632118334Speter    delete_failure_queue ();
632218334Speter  delete_temp_files ();
632318334Speter
632450599Sobrien  if (print_help_list)
632550599Sobrien    {
632690277Sobrien      printf (("\nFor bug reporting instructions, please see:\n"));
632757849Sobrien      printf ("%s\n", GCCBUGURL);
632850599Sobrien    }
632990277Sobrien
633090277Sobrien  return (signal_count != 0 ? 2
633190277Sobrien	  : error_count > 0 ? (pass_exit_codes ? greatest_status : 1)
633290277Sobrien	  : 0);
633318334Speter}
633418334Speter
633518334Speter/* Find the proper compilation spec for the file name NAME,
633618334Speter   whose length is LENGTH.  LANGUAGE is the specified language,
633750599Sobrien   or 0 if this file is to be passed to the linker.  */
633818334Speter
633918334Speterstatic struct compiler *
634018334Speterlookup_compiler (name, length, language)
634152520Sobrien     const char *name;
634250599Sobrien     size_t length;
634352520Sobrien     const char *language;
634418334Speter{
634518334Speter  struct compiler *cp;
634618334Speter
634790277Sobrien  /* If this was specified by the user to be a linker input, indicate that.  */
634850599Sobrien  if (language != 0 && language[0] == '*')
634950599Sobrien    return 0;
635050599Sobrien
635150599Sobrien  /* Otherwise, look for the language, if one is spec'd.  */
635218334Speter  if (language != 0)
635318334Speter    {
635418334Speter      for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
635550599Sobrien	if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
635650599Sobrien	  return cp;
635750599Sobrien
635818334Speter      error ("language %s not recognized", language);
635950599Sobrien      return 0;
636018334Speter    }
636118334Speter
636218334Speter  /* Look for a suffix.  */
636318334Speter  for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
636418334Speter    {
636518334Speter      if (/* The suffix `-' matches only the file name `-'.  */
636618334Speter	  (!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
636750599Sobrien	  || (strlen (cp->suffix) < length
636850599Sobrien	      /* See if the suffix matches the end of NAME.  */
636950599Sobrien	      && !strcmp (cp->suffix,
637050599Sobrien			  name + length - strlen (cp->suffix))
637150599Sobrien	 ))
637290277Sobrien        break;
637390277Sobrien    }
637450599Sobrien
637590277Sobrien#if defined (OS2) ||defined (HAVE_DOS_BASED_FILE_SYSTEM)
637690277Sobrien  /* look again, but case-insensitively this time.  */
637790277Sobrien  if (cp < compilers)
637890277Sobrien    for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
637990277Sobrien      {
638090277Sobrien	if (/* The suffix `-' matches only the file name `-'.  */
638190277Sobrien	    (!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
638290277Sobrien	    || (strlen (cp->suffix) < length
638390277Sobrien		/* See if the suffix matches the end of NAME.  */
638490277Sobrien		&& ((!strcmp (cp->suffix,
638590277Sobrien			     name + length - strlen (cp->suffix))
638690277Sobrien		     || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
638790277Sobrien		    && !strcasecmp (cp->suffix,
638890277Sobrien				    name + length - strlen (cp->suffix)))
638990277Sobrien	   ))
639090277Sobrien	  break;
639190277Sobrien      }
639290277Sobrien#endif
639350599Sobrien
639490277Sobrien  if (cp >= compilers)
639590277Sobrien    {
639690277Sobrien      if (cp->spec[0] != '@')
639790277Sobrien	/* A non-alias entry: return it.  */
639890277Sobrien	return cp;
639990277Sobrien
640090277Sobrien      /* An alias entry maps a suffix to a language.
640190277Sobrien	 Search for the language; pass 0 for NAME and LENGTH
640290277Sobrien	 to avoid infinite recursion if language not found.  */
640390277Sobrien      return lookup_compiler (NULL, 0, cp->spec + 1);
640418334Speter    }
640518334Speter  return 0;
640618334Speter}
640718334Speter
640818334Speterstatic char *
640918334Spetersave_string (s, len)
641090277Sobrien     const char *s;
641190277Sobrien     int len;
641218334Speter{
641390277Sobrien  char *result = xmalloc (len + 1);
641418334Speter
641590277Sobrien  memcpy (result, s, len);
641618334Speter  result[len] = 0;
641718334Speter  return result;
641818334Speter}
641918334Speter
642090277Sobrienvoid
642118334Speterpfatal_with_name (name)
642252520Sobrien     const char *name;
642318334Speter{
642452520Sobrien  perror_with_name (name);
642552520Sobrien  delete_temp_files ();
642652520Sobrien  exit (1);
642718334Speter}
642818334Speter
642918334Speterstatic void
643018334Speterperror_with_name (name)
643152520Sobrien     const char *name;
643218334Speter{
643352520Sobrien  error ("%s: %s", name, xstrerror (errno));
643418334Speter}
643518334Speter
643618334Speterstatic void
643750599Sobrienpfatal_pexecute (errmsg_fmt, errmsg_arg)
643852520Sobrien     const char *errmsg_fmt;
643952520Sobrien     const char *errmsg_arg;
644018334Speter{
644150599Sobrien  if (errmsg_arg)
644250599Sobrien    {
644352520Sobrien      int save_errno = errno;
644452520Sobrien
644550599Sobrien      /* Space for trailing '\0' is in %s.  */
644650599Sobrien      char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg));
644750599Sobrien      sprintf (msg, errmsg_fmt, errmsg_arg);
644850599Sobrien      errmsg_fmt = msg;
644952520Sobrien
645052520Sobrien      errno = save_errno;
645150599Sobrien    }
645250599Sobrien
645352520Sobrien  pfatal_with_name (errmsg_fmt);
645418334Speter}
645518334Speter
645690277Sobrien/* Output an error message and exit */
645718334Speter
645818334Spetervoid
645918334Speterfancy_abort ()
646018334Speter{
646190277Sobrien  fatal ("internal gcc abort");
646218334Speter}
646318334Speter
646418334Speter/* Output an error message and exit */
646518334Speter
646652520Sobrienvoid
646790277Sobrienfatal VPARAMS ((const char *msgid, ...))
646818334Speter{
646990277Sobrien  VA_OPEN (ap, msgid);
647090277Sobrien  VA_FIXEDARG (ap, const char *, msgid);
647118334Speter
647218334Speter  fprintf (stderr, "%s: ", programname);
647352520Sobrien  vfprintf (stderr, _(msgid), ap);
647490277Sobrien  VA_CLOSE (ap);
647518334Speter  fprintf (stderr, "\n");
647618334Speter  delete_temp_files ();
647718334Speter  exit (1);
647818334Speter}
647918334Speter
648090277Sobrienvoid
648190277Sobrienerror VPARAMS ((const char *msgid, ...))
648218334Speter{
648390277Sobrien  VA_OPEN (ap, msgid);
648490277Sobrien  VA_FIXEDARG (ap, const char *, msgid);
648518334Speter
648618334Speter  fprintf (stderr, "%s: ", programname);
648752520Sobrien  vfprintf (stderr, _(msgid), ap);
648890277Sobrien  VA_CLOSE (ap);
648918334Speter
649018334Speter  fprintf (stderr, "\n");
649118334Speter}
649252520Sobrien
649352520Sobrienstatic void
649490277Sobriennotice VPARAMS ((const char *msgid, ...))
649552520Sobrien{
649690277Sobrien  VA_OPEN (ap, msgid);
649790277Sobrien  VA_FIXEDARG (ap, const char *, msgid);
649852520Sobrien
649952520Sobrien  vfprintf (stderr, _(msgid), ap);
650090277Sobrien  VA_CLOSE (ap);
650152520Sobrien}
650218334Speter
650318334Speterstatic void
650418334Spetervalidate_all_switches ()
650518334Speter{
650618334Speter  struct compiler *comp;
650790277Sobrien  const char *p;
650890277Sobrien  char c;
650918334Speter  struct spec_list *spec;
651018334Speter
651190277Sobrien  for (comp = compilers; comp->spec; comp++)
651218334Speter    {
651390277Sobrien      p = comp->spec;
651490277Sobrien      while ((c = *p++))
651590277Sobrien	if (c == '%' && *p == '{')
651690277Sobrien	  /* We have a switch spec.  */
651790277Sobrien	  validate_switches (p + 1);
651818334Speter    }
651918334Speter
652090277Sobrien  /* Look through the linked list of specs read from the specs file.  */
652190277Sobrien  for (spec = specs; spec; spec = spec->next)
652218334Speter    {
652350599Sobrien      p = *(spec->ptr_spec);
652450599Sobrien      while ((c = *p++))
652518334Speter	if (c == '%' && *p == '{')
652618334Speter	  /* We have a switch spec.  */
652718334Speter	  validate_switches (p + 1);
652818334Speter    }
652918334Speter
653018334Speter  p = link_command_spec;
653150599Sobrien  while ((c = *p++))
653218334Speter    if (c == '%' && *p == '{')
653318334Speter      /* We have a switch spec.  */
653418334Speter      validate_switches (p + 1);
653518334Speter}
653618334Speter
653718334Speter/* Look at the switch-name that comes after START
653818334Speter   and mark as valid all supplied switches that match it.  */
653918334Speter
654018334Speterstatic void
654118334Spetervalidate_switches (start)
654252520Sobrien     const char *start;
654318334Speter{
654490277Sobrien  const char *p = start;
654552520Sobrien  const char *filter;
654690277Sobrien  int i;
654790277Sobrien  int suffix;
654818334Speter
654918334Speter  if (*p == '|')
655018334Speter    ++p;
655118334Speter
655290277Sobriennext_member:
655318334Speter  if (*p == '!')
655418334Speter    ++p;
655518334Speter
655690277Sobrien  suffix = 0;
655718334Speter  if (*p == '.')
655818334Speter    suffix = 1, ++p;
655918334Speter
656018334Speter  filter = p;
656190277Sobrien  while (*p != ':' && *p != '}' && *p != '|' && *p != '&')
656290277Sobrien    p++;
656318334Speter
656418334Speter  if (suffix)
656518334Speter    ;
656618334Speter  else if (p[-1] == '*')
656718334Speter    {
656818334Speter      /* Mark all matching switches as valid.  */
656918334Speter      for (i = 0; i < n_switches; i++)
657090277Sobrien	if (!strncmp (switches[i].part1, filter, p - filter - 1))
657152520Sobrien	  switches[i].validated = 1;
657218334Speter    }
657318334Speter  else
657418334Speter    {
657518334Speter      /* Mark an exact matching switch as valid.  */
657618334Speter      for (i = 0; i < n_switches; i++)
657718334Speter	{
657818334Speter	  if (!strncmp (switches[i].part1, filter, p - filter)
657918334Speter	      && switches[i].part1[p - filter] == 0)
658052520Sobrien	    switches[i].validated = 1;
658118334Speter	}
658218334Speter    }
658390277Sobrien
658490277Sobrien  if (*p++ == '|' || p[-1] == '&')
658590277Sobrien    goto next_member;
658618334Speter}
658718334Speter
658850599Sobrien/* Check whether a particular argument was used.  The first time we
658950599Sobrien   canonicalize the switches to keep only the ones we care about.  */
659018334Speter
659118334Speterstatic int
659218334Speterused_arg (p, len)
659352520Sobrien     const char *p;
659418334Speter     int len;
659518334Speter{
659690277Sobrien  struct mswitchstr
659790277Sobrien  {
659890277Sobrien    const char *str;
659990277Sobrien    const char *replace;
660050599Sobrien    int len;
660150599Sobrien    int rep_len;
660250599Sobrien  };
660318334Speter
660450599Sobrien  static struct mswitchstr *mswitches;
660550599Sobrien  static int n_mswitches;
660650599Sobrien  int i, j;
660750599Sobrien
660850599Sobrien  if (!mswitches)
660950599Sobrien    {
661050599Sobrien      struct mswitchstr *matches;
661190277Sobrien      const char *q;
661250599Sobrien      int cnt = 0;
661350599Sobrien
661490277Sobrien      /* Break multilib_matches into the component strings of string
661590277Sobrien         and replacement string.  */
661650599Sobrien      for (q = multilib_matches; *q != '\0'; q++)
661750599Sobrien	if (*q == ';')
661850599Sobrien	  cnt++;
661950599Sobrien
662090277Sobrien      matches =
662190277Sobrien	(struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
662250599Sobrien      i = 0;
662350599Sobrien      q = multilib_matches;
662450599Sobrien      while (*q != '\0')
662550599Sobrien	{
662650599Sobrien	  matches[i].str = q;
662750599Sobrien	  while (*q != ' ')
662850599Sobrien	    {
662950599Sobrien	      if (*q == '\0')
663050599Sobrien		abort ();
663150599Sobrien	      q++;
663250599Sobrien	    }
663350599Sobrien	  matches[i].len = q - matches[i].str;
663450599Sobrien
663550599Sobrien	  matches[i].replace = ++q;
663650599Sobrien	  while (*q != ';' && *q != '\0')
663750599Sobrien	    {
663850599Sobrien	      if (*q == ' ')
663950599Sobrien		abort ();
664050599Sobrien	      q++;
664150599Sobrien	    }
664250599Sobrien	  matches[i].rep_len = q - matches[i].replace;
664350599Sobrien	  i++;
664450599Sobrien	  if (*q == ';')
664590277Sobrien	    q++;
664650599Sobrien	}
664750599Sobrien
664850599Sobrien      /* Now build a list of the replacement string for switches that we care
664950599Sobrien	 about.  Make sure we allocate at least one entry.  This prevents
665050599Sobrien	 xmalloc from calling fatal, and prevents us from re-executing this
665150599Sobrien	 block of code.  */
665250599Sobrien      mswitches
665350599Sobrien	= (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr))
665450599Sobrien					 * (n_switches ? n_switches : 1));
665550599Sobrien      for (i = 0; i < n_switches; i++)
665650599Sobrien	{
665750599Sobrien	  int xlen = strlen (switches[i].part1);
665850599Sobrien	  for (j = 0; j < cnt; j++)
665990277Sobrien	    if (xlen == matches[j].len
666090277Sobrien		&& ! strncmp (switches[i].part1, matches[j].str, xlen))
666150599Sobrien	      {
666250599Sobrien		mswitches[n_mswitches].str = matches[j].replace;
666350599Sobrien		mswitches[n_mswitches].len = matches[j].rep_len;
666490277Sobrien		mswitches[n_mswitches].replace = (char *) 0;
666550599Sobrien		mswitches[n_mswitches].rep_len = 0;
666650599Sobrien		n_mswitches++;
666750599Sobrien		break;
666850599Sobrien	      }
666950599Sobrien	}
667050599Sobrien    }
667150599Sobrien
667250599Sobrien  for (i = 0; i < n_mswitches; i++)
667350599Sobrien    if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
667418334Speter      return 1;
667550599Sobrien
667618334Speter  return 0;
667718334Speter}
667818334Speter
667918334Speterstatic int
668018334Speterdefault_arg (p, len)
668152520Sobrien     const char *p;
668218334Speter     int len;
668318334Speter{
668490277Sobrien  const char *start, *end;
668518334Speter
668690277Sobrien  for (start = multilib_defaults; *start != '\0'; start = end + 1)
668750599Sobrien    {
668850599Sobrien      while (*start == ' ' || *start == '\t')
668950599Sobrien	start++;
669018334Speter
669150599Sobrien      if (*start == '\0')
669250599Sobrien	break;
669350599Sobrien
669490277Sobrien      for (end = start + 1; *end != ' ' && *end != '\t' && *end != '\0'; end++)
669550599Sobrien	;
669650599Sobrien
669750599Sobrien      if ((end - start) == len && strncmp (p, start, len) == 0)
669850599Sobrien	return 1;
669950599Sobrien
670050599Sobrien      if (*end == '\0')
670150599Sobrien	break;
670250599Sobrien    }
670350599Sobrien
670418334Speter  return 0;
670518334Speter}
670618334Speter
670790277Sobrien/* Work out the subdirectory to use based on the options. The format of
670890277Sobrien   multilib_select is a list of elements. Each element is a subdirectory
670990277Sobrien   name followed by a list of options followed by a semicolon. The format
671090277Sobrien   of multilib_exclusions is the same, but without the preceding
671190277Sobrien   directory. First gcc will check the exclusions, if none of the options
671290277Sobrien   beginning with an exclamation point are present, and all of the other
671390277Sobrien   options are present, then we will ignore this completely. Passing
671490277Sobrien   that, gcc will consider each multilib_select in turn using the same
671590277Sobrien   rules for matching the options. If a match is found, that subdirectory
671690277Sobrien   will be used.  */
671718334Speter
671818334Speterstatic void
671918334Speterset_multilib_dir ()
672018334Speter{
672190277Sobrien  const char *p;
672290277Sobrien  unsigned int this_path_len;
672390277Sobrien  const char *this_path, *this_arg;
672418334Speter  int not_arg;
672518334Speter  int ok;
672618334Speter
672790277Sobrien  p = multilib_exclusions;
672818334Speter  while (*p != '\0')
672918334Speter    {
673018334Speter      /* Ignore newlines.  */
673118334Speter      if (*p == '\n')
673218334Speter	{
673318334Speter	  ++p;
673418334Speter	  continue;
673518334Speter	}
673618334Speter
673790277Sobrien      /* Check the arguments.  */
673890277Sobrien      ok = 1;
673990277Sobrien      while (*p != ';')
674090277Sobrien	{
674190277Sobrien	  if (*p == '\0')
674290277Sobrien	    abort ();
674390277Sobrien
674490277Sobrien	  if (! ok)
674590277Sobrien	    {
674690277Sobrien	      ++p;
674790277Sobrien	      continue;
674890277Sobrien	    }
674990277Sobrien
675090277Sobrien	  this_arg = p;
675190277Sobrien	  while (*p != ' ' && *p != ';')
675290277Sobrien	    {
675390277Sobrien	      if (*p == '\0')
675490277Sobrien		abort ();
675590277Sobrien	      ++p;
675690277Sobrien	    }
675790277Sobrien
675890277Sobrien	  if (*this_arg != '!')
675990277Sobrien	    not_arg = 0;
676090277Sobrien	  else
676190277Sobrien	    {
676290277Sobrien	      not_arg = 1;
676390277Sobrien	      ++this_arg;
676490277Sobrien	    }
676590277Sobrien
676690277Sobrien	  ok = used_arg (this_arg, p - this_arg);
676790277Sobrien	  if (not_arg)
676890277Sobrien	    ok = ! ok;
676990277Sobrien
677090277Sobrien	  if (*p == ' ')
677190277Sobrien	    ++p;
677290277Sobrien	}
677390277Sobrien
677490277Sobrien      if (ok)
677590277Sobrien	return;
677690277Sobrien
677790277Sobrien      ++p;
677890277Sobrien    }
677990277Sobrien
678090277Sobrien  p = multilib_select;
678190277Sobrien  while (*p != '\0')
678290277Sobrien    {
678390277Sobrien      /* Ignore newlines.  */
678490277Sobrien      if (*p == '\n')
678590277Sobrien	{
678690277Sobrien	  ++p;
678790277Sobrien	  continue;
678890277Sobrien	}
678990277Sobrien
679018334Speter      /* Get the initial path.  */
679118334Speter      this_path = p;
679218334Speter      while (*p != ' ')
679318334Speter	{
679418334Speter	  if (*p == '\0')
679518334Speter	    abort ();
679618334Speter	  ++p;
679718334Speter	}
679818334Speter      this_path_len = p - this_path;
679918334Speter
680018334Speter      /* Check the arguments.  */
680118334Speter      ok = 1;
680218334Speter      ++p;
680318334Speter      while (*p != ';')
680418334Speter	{
680518334Speter	  if (*p == '\0')
680618334Speter	    abort ();
680718334Speter
680818334Speter	  if (! ok)
680918334Speter	    {
681018334Speter	      ++p;
681118334Speter	      continue;
681218334Speter	    }
681318334Speter
681418334Speter	  this_arg = p;
681518334Speter	  while (*p != ' ' && *p != ';')
681618334Speter	    {
681718334Speter	      if (*p == '\0')
681818334Speter		abort ();
681918334Speter	      ++p;
682018334Speter	    }
682118334Speter
682218334Speter	  if (*this_arg != '!')
682318334Speter	    not_arg = 0;
682418334Speter	  else
682518334Speter	    {
682618334Speter	      not_arg = 1;
682718334Speter	      ++this_arg;
682818334Speter	    }
682918334Speter
683018334Speter	  /* If this is a default argument, we can just ignore it.
683118334Speter	     This is true even if this_arg begins with '!'.  Beginning
683218334Speter	     with '!' does not mean that this argument is necessarily
683318334Speter	     inappropriate for this library: it merely means that
683418334Speter	     there is a more specific library which uses this
683518334Speter	     argument.  If this argument is a default, we need not
683618334Speter	     consider that more specific library.  */
683718334Speter	  if (! default_arg (this_arg, p - this_arg))
683818334Speter	    {
683918334Speter	      ok = used_arg (this_arg, p - this_arg);
684018334Speter	      if (not_arg)
684118334Speter		ok = ! ok;
684218334Speter	    }
684318334Speter
684418334Speter	  if (*p == ' ')
684518334Speter	    ++p;
684618334Speter	}
684718334Speter
684818334Speter      if (ok)
684918334Speter	{
685018334Speter	  if (this_path_len != 1
685118334Speter	      || this_path[0] != '.')
685218334Speter	    {
685390277Sobrien	      char *new_multilib_dir = xmalloc (this_path_len + 1);
685452520Sobrien	      strncpy (new_multilib_dir, this_path, this_path_len);
685552520Sobrien	      new_multilib_dir[this_path_len] = '\0';
685652520Sobrien	      multilib_dir = new_multilib_dir;
685718334Speter	    }
685818334Speter	  break;
685918334Speter	}
686018334Speter
686118334Speter      ++p;
686290277Sobrien    }
686318334Speter}
686418334Speter
686518334Speter/* Print out the multiple library subdirectory selection
686618334Speter   information.  This prints out a series of lines.  Each line looks
686718334Speter   like SUBDIRECTORY;@OPTION@OPTION, with as many options as is
686818334Speter   required.  Only the desired options are printed out, the negative
686918334Speter   matches.  The options are print without a leading dash.  There are
687018334Speter   no spaces to make it easy to use the information in the shell.
687118334Speter   Each subdirectory is printed only once.  This assumes the ordering
687290277Sobrien   generated by the genmultilib script. Also, we leave out ones that match
687390277Sobrien   the exclusions.  */
687418334Speter
687518334Speterstatic void
687618334Speterprint_multilib_info ()
687718334Speter{
687890277Sobrien  const char *p = multilib_select;
687990277Sobrien  const char *last_path = 0, *this_path;
688018334Speter  int skip;
688190277Sobrien  unsigned int last_path_len = 0;
688218334Speter
688318334Speter  while (*p != '\0')
688418334Speter    {
688590277Sobrien      skip = 0;
688618334Speter      /* Ignore newlines.  */
688718334Speter      if (*p == '\n')
688818334Speter	{
688918334Speter	  ++p;
689018334Speter	  continue;
689118334Speter	}
689218334Speter
689318334Speter      /* Get the initial path.  */
689418334Speter      this_path = p;
689518334Speter      while (*p != ' ')
689618334Speter	{
689718334Speter	  if (*p == '\0')
689818334Speter	    abort ();
689918334Speter	  ++p;
690018334Speter	}
690118334Speter
690290277Sobrien      /* Check for matches with the multilib_exclusions. We don't bother
690390277Sobrien         with the '!' in either list. If any of the exclusion rules match
690490277Sobrien         all of its options with the select rule, we skip it.  */
690590277Sobrien      {
690690277Sobrien	const char *e = multilib_exclusions;
690790277Sobrien	const char *this_arg;
690818334Speter
690990277Sobrien	while (*e != '\0')
691090277Sobrien	  {
691190277Sobrien	    int m = 1;
691290277Sobrien	    /* Ignore newlines.  */
691390277Sobrien	    if (*e == '\n')
691490277Sobrien	      {
691590277Sobrien		++e;
691690277Sobrien		continue;
691790277Sobrien	      }
691818334Speter
691990277Sobrien	    /* Check the arguments.  */
692090277Sobrien	    while (*e != ';')
692190277Sobrien	      {
692290277Sobrien		const char *q;
692390277Sobrien		int mp = 0;
692490277Sobrien
692590277Sobrien		if (*e == '\0')
692690277Sobrien		  abort ();
692790277Sobrien
692890277Sobrien		if (! m)
692990277Sobrien		  {
693090277Sobrien		    ++e;
693190277Sobrien		    continue;
693290277Sobrien		  }
693390277Sobrien
693490277Sobrien		this_arg = e;
693590277Sobrien
693690277Sobrien		while (*e != ' ' && *e != ';')
693790277Sobrien		  {
693890277Sobrien		    if (*e == '\0')
693990277Sobrien		      abort ();
694090277Sobrien		    ++e;
694190277Sobrien		  }
694290277Sobrien
694390277Sobrien		q = p + 1;
694490277Sobrien		while (*q != ';')
694590277Sobrien		  {
694690277Sobrien		    const char *arg;
694790277Sobrien		    int len = e - this_arg;
694890277Sobrien
694990277Sobrien		    if (*q == '\0')
695090277Sobrien		      abort ();
695190277Sobrien
695290277Sobrien		    arg = q;
695390277Sobrien
695490277Sobrien		    while (*q != ' ' && *q != ';')
695590277Sobrien		      {
695690277Sobrien			if (*q == '\0')
695790277Sobrien			  abort ();
695890277Sobrien			++q;
695990277Sobrien		      }
696090277Sobrien
696190277Sobrien		    if (! strncmp (arg, this_arg, (len < q - arg) ? q - arg : len) ||
696290277Sobrien			default_arg (this_arg, e - this_arg))
696390277Sobrien		      {
696490277Sobrien			mp = 1;
696590277Sobrien			break;
696690277Sobrien		      }
696790277Sobrien
696890277Sobrien		    if (*q == ' ')
696990277Sobrien		      ++q;
697090277Sobrien		  }
697190277Sobrien
697290277Sobrien		if (! mp)
697390277Sobrien		  m = 0;
697490277Sobrien
697590277Sobrien		if (*e == ' ')
697690277Sobrien		  ++e;
697790277Sobrien	      }
697890277Sobrien
697990277Sobrien	    if (m)
698090277Sobrien	      {
698190277Sobrien		skip = 1;
698290277Sobrien		break;
698390277Sobrien	      }
698490277Sobrien
698590277Sobrien	    if (*e != '\0')
698690277Sobrien	      ++e;
698790277Sobrien	  }
698890277Sobrien      }
698990277Sobrien
699090277Sobrien      if (! skip)
699190277Sobrien	{
699290277Sobrien	  /* If this is a duplicate, skip it.  */
699390277Sobrien	  skip = (last_path != 0 && (unsigned int) (p - this_path) == last_path_len
699490277Sobrien		  && ! strncmp (last_path, this_path, last_path_len));
699590277Sobrien
699690277Sobrien	  last_path = this_path;
699790277Sobrien	  last_path_len = p - this_path;
699890277Sobrien	}
699990277Sobrien
700018334Speter      /* If this directory requires any default arguments, we can skip
700118334Speter	 it.  We will already have printed a directory identical to
700218334Speter	 this one which does not require that default argument.  */
700318334Speter      if (! skip)
700418334Speter	{
700590277Sobrien	  const char *q;
700618334Speter
700718334Speter	  q = p + 1;
700818334Speter	  while (*q != ';')
700918334Speter	    {
701090277Sobrien	      const char *arg;
701118334Speter
701218334Speter	      if (*q == '\0')
701318334Speter		abort ();
701418334Speter
701518334Speter	      if (*q == '!')
701618334Speter		arg = NULL;
701718334Speter	      else
701818334Speter		arg = q;
701918334Speter
702018334Speter	      while (*q != ' ' && *q != ';')
702118334Speter		{
702218334Speter		  if (*q == '\0')
702318334Speter		    abort ();
702418334Speter		  ++q;
702518334Speter		}
702618334Speter
702718334Speter	      if (arg != NULL
702818334Speter		  && default_arg (arg, q - arg))
702918334Speter		{
703018334Speter		  skip = 1;
703118334Speter		  break;
703218334Speter		}
703318334Speter
703418334Speter	      if (*q == ' ')
703518334Speter		++q;
703618334Speter	    }
703718334Speter	}
703818334Speter
703918334Speter      if (! skip)
704018334Speter	{
704190277Sobrien	  const char *p1;
704218334Speter
704318334Speter	  for (p1 = last_path; p1 < p; p1++)
704418334Speter	    putchar (*p1);
704518334Speter	  putchar (';');
704618334Speter	}
704718334Speter
704818334Speter      ++p;
704918334Speter      while (*p != ';')
705018334Speter	{
705118334Speter	  int use_arg;
705218334Speter
705318334Speter	  if (*p == '\0')
705418334Speter	    abort ();
705518334Speter
705618334Speter	  if (skip)
705718334Speter	    {
705818334Speter	      ++p;
705918334Speter	      continue;
706018334Speter	    }
706118334Speter
706218334Speter	  use_arg = *p != '!';
706318334Speter
706418334Speter	  if (use_arg)
706518334Speter	    putchar ('@');
706618334Speter
706718334Speter	  while (*p != ' ' && *p != ';')
706818334Speter	    {
706918334Speter	      if (*p == '\0')
707018334Speter		abort ();
707118334Speter	      if (use_arg)
707218334Speter		putchar (*p);
707318334Speter	      ++p;
707418334Speter	    }
707518334Speter
707618334Speter	  if (*p == ' ')
707718334Speter	    ++p;
707818334Speter	}
707918334Speter
708018334Speter      if (! skip)
708150599Sobrien	{
708290277Sobrien	  /* If there are extra options, print them now.  */
708350599Sobrien	  if (multilib_extra && *multilib_extra)
708450599Sobrien	    {
708550599Sobrien	      int print_at = TRUE;
708690277Sobrien	      const char *q;
708718334Speter
708850599Sobrien	      for (q = multilib_extra; *q != '\0'; q++)
708950599Sobrien		{
709050599Sobrien		  if (*q == ' ')
709150599Sobrien		    print_at = TRUE;
709250599Sobrien		  else
709350599Sobrien		    {
709450599Sobrien		      if (print_at)
709550599Sobrien			putchar ('@');
709650599Sobrien		      putchar (*q);
709750599Sobrien		      print_at = FALSE;
709850599Sobrien		    }
709950599Sobrien		}
710050599Sobrien	    }
710190277Sobrien
710250599Sobrien	  putchar ('\n');
710350599Sobrien	}
710450599Sobrien
710518334Speter      ++p;
710618334Speter    }
710718334Speter}
7108