+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)g++.c 6.5 (Berkeley) 5/8/91";
+#endif /* not lint */
+
+/* Compiler driver program that can handle many languages.
+ Copyright (C) 1987,1989 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+This paragraph is here to try to keep Sun CC from dying.
+The number of chars here seems crucial!!!! */
+
+void record_temp_file ();
+\f
+/* This program is the user interface to the C compiler and possibly to
+other compilers. It is used because compilation is a complicated procedure
+which involves running several programs and passing temporary files between
+them, forwarding the users switches to those programs selectively,
+and deleting the temporary files at the end.
+
+CC recognizes how to compile each input file by suffixes in the file names.
+Once it knows which kind of compilation to perform, the procedure for
+compilation is specified by a string called a "spec".
+
+Specs are strings containing lines, each of which (if not blank)
+is made up of a program name, and arguments separated by spaces.
+The program name must be exact and start from root, since no path
+is searched and it is unreliable to depend on the current working directory.
+Redirection of input or output is not supported; the subprograms must
+accept filenames saying what files to read and write.
+
+In addition, the specs can contain %-sequences to substitute variable text
+or for conditional text. Here is a table of all defined %-sequences.
+Note that spaces are not generated automatically around the results of
+expanding these sequences; therefore, you can concatenate them together
+or with constant text in a single argument.
+
+ %% substitute one % into the program name or argument.
+ %i substitute the name of the input file being processed.
+ %b substitute the basename of the input file being processed.
+ This is the substring up to (and not including) the last period.
+ %g substitute the temporary-file-name-base. This is a string chosen
+ once per compilation. Different temporary file names are made by
+ concatenation of constant strings on the end, as in `%g.s'.
+ %g also has the same effect of %d.
+ %d marks the argument containing or following the %d as a
+ temporary file name, so that that file will be deleted if CC exits
+ successfully. Unlike %g, this contributes no text to the argument.
+ %w marks the argument containing or following the %w as the
+ "output file" of this compilation. This puts the argument
+ into the sequence of arguments that %o will substitute later.
+ %o substitutes the names of all the output files, with spaces
+ automatically placed around them. You should write spaces
+ around the %o as well or the results are undefined.
+ %o is for use in the specs for running the linker.
+ Input files whose names have no recognized suffix are not compiled
+ at all, but they are included among the output files, so they will
+ be linked.
+ %p substitutes the standard macro predefinitions for the
+ current target machine. Use this when running cpp.
+ %P like %p, but puts `__' before and after the name of each macro.
+ This is for ANSI C.
+ %s current argument is the name of a library or startup file of some sort.
+ Search for that file in a standard list of directories
+ and substitute the full pathname found.
+ %eSTR Print STR as an error message. STR is terminated by a newline.
+ Use this when inconsistent options are detected.
+ %a process ASM_SPEC as a spec.
+ This allows config.h to specify part of the spec for running as.
+ %l process LINK_SPEC as a spec.
+ %L process LIB_SPEC as a spec.
+ %S process STARTFILE_SPEC as a spec. A capital S is actually used here.
+ %c process SIGNED_CHAR_SPEC as a spec.
+ %C process CPP_SPEC as a spec. A capital C is actually used here.
+ %1 process CC1_SPEC as a spec.
+ %{S} substitutes the -S switch, if that switch was given to CC.
+ If that switch was not specified, this substitutes nothing.
+ Here S is a metasyntactic variable.
+ %{S*} substitutes all the switches specified to CC whose names start
+ with -S. This is used for -o, -D, -I, etc; switches that take
+ arguments. CC considers `-o foo' as being one switch whose
+ name starts with `o'. %{o*} would substitute this text,
+ including the space; thus, two arguments would be generated.
+ %{S:X} substitutes X, but only if the -S switch was given to CC.
+ %{!S:X} substitutes X, but only if the -S switch was NOT given to CC.
+ %{|S:X} like %{S:X}, but if no S switch, substitute `-'.
+ %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
+
+The conditional text X in a %{S:X} or %{!S:X} construct may contain
+other nested % constructs or spaces, or even newlines.
+They are processed as usual, as described above.
+
+The character | is used to indicate that a command should be piped to
+the following command, but only if -pipe is specified.
+
+Note that it is built into CC which switches take arguments and which
+do not. You might think it would be useful to generalize this to
+allow each compiler's spec to say which switches take arguments. But
+this cannot be done in a consistent fashion. CC cannot even decide
+which input files have been specified without knowing which switches
+take arguments, and it must know which input files to compile in order
+to tell which compilers to run.
+
+CC also knows implicitly that arguments starting in `-l' are to
+be treated as compiler output files, and passed to the linker in their proper
+position among the other output files.
+
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/file.h>
+
+#include "config.h"
+#include "obstack.h"
+#include "gvarargs.h"
+
+#ifdef USG
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#define vfork fork
+#endif /* USG */
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+extern int xmalloc ();
+extern void free ();
+
+/* If a stage of compilation returns an exit status >= 1,
+ compilation of that file ceases. */
+
+#define MIN_FATAL_STATUS 1
+
+/* This is the obstack which we use to allocate many strings. */
+
+struct obstack obstack;
+
+char *handle_braces ();
+char *save_string ();
+char *concat ();
+int do_spec ();
+int do_spec_1 ();
+char *find_file ();
+static char *find_exec_file ();
+void validate_switches ();
+void validate_all_switches ();
+void fancy_abort ();
+
+/* config.h can define ASM_SPEC to provide extra args to the assembler
+ or extra switch-translations. */
+#ifndef ASM_SPEC
+#define ASM_SPEC ""
+#endif
+
+/* config.h can define CPP_SPEC to provide extra args to the C preprocessor
+ or extra switch-translations. */
+#ifndef CPP_SPEC
+#define CPP_SPEC ""
+#endif
+
+/* config.h can define CC1_SPEC to provide extra args to cc1
+ or extra switch-translations. */
+#ifndef CC1_SPEC
+#define CC1_SPEC ""
+#endif
+
+/* config.h can define LINK_SPEC to provide extra args to the linker
+ or extra switch-translations. */
+#ifndef LINK_SPEC
+#define LINK_SPEC ""
+#endif
+
+/* config.h can define LIB_SPEC to override the default libraries. */
+#ifndef LIB_SPEC
+#define LIB_SPEC "%{!p:%{!pg:-lm -lc}}%{p:-lm_p -lc_p}%{pg:-lm_p -lc_p}"
+#endif
+
+/* config.h can define STARTFILE_SPEC to override the default crt0 files. */
+#ifndef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}"
+#endif
+
+/* This spec is used for telling cpp whether char is signed or not. */
+#define SIGNED_CHAR_SPEC \
+ (DEFAULT_SIGNED_CHAR ? "%{funsigned-char:-D__CHAR_UNSIGNED__}" \
+ : "%{!fsigned-char:-D__CHAR_UNSIGNED__}")
+
+/* This defines which switch letters take arguments. */
+
+#ifndef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
+ || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
+ || (CHAR) == 'I' || (CHAR) == 'Y' || (CHAR) == 'm' \
+ || (CHAR) == 'L' || (CHAR) == 'i')
+#endif
+
+/* This defines which multi-letter switches take arguments. */
+
+#ifndef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR) (!strcmp (STR, "Tdata"))
+#endif
+
+/* This structure says how to run one compiler, and when to do so. */
+
+struct compiler
+{
+ char *suffix; /* Use this compiler for input files
+ whose names end in this suffix. */
+ char *spec; /* To use this compiler, pass this spec
+ to do_spec. */
+};
+
+#define cplusplus_string \
+ "cpp -+ %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{i*} \
+ -undef -D__GNUC__ -D__GNUG__ -D__cplusplus %p %P\
+ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\
+ %{Wcomment*} %{Wtrigraphs} %{Wall} %C\
+ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\
+ %{!M*:%{!E:cc1plus %{!pipe:%g.cpp} %1\
+ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{+e*} %{a}\
+ %{g} %{g0} %{O} %{W*} %{w} %{pedantic} %{traditional}\
+ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p} %{xref}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\
+ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
+ %{!pipe:%g.s}\n }}}"
+
+/* Here are the specs for compiling files with various known suffixes.
+ A file that does not end in any of these suffixes will be passed
+ unchanged to the loader and nothing else will be done to it. */
+
+struct compiler compilers[] =
+{
+ {".c",
+#if 0
+ "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{M*} %{i*} %{trigraphs} -undef \
+ -D__GNUC__ %{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!ansi:%p} %P\
+ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\
+ %{Wcomment*} %{Wtrigraphs} %{Wall} %C\
+ %i %{!M*:%{!E:%{!pipe:%g.cpp}}}%{E:%{o*}}%{M*:%{o*}} |\n\
+ %{!M*:%{!E:cc1 %{!pipe:%g.cpp} %1 \
+ %{!Q:-quiet} -dumpbase %i %{Y*} %{d*} %{m*} %{f*} %{a}\
+ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\
+ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p} %{xref}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\
+ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
+ %{!pipe:%g.s}\n }}}"
+#else
+ cplusplus_string
+#endif
+ },
+
+ {".cc",
+ cplusplus_string},
+ {".C",
+ cplusplus_string},
+ {".cxx",
+ cplusplus_string},
+
+ {".i",
+ "cc1 %i %1 %{!Q:-quiet} %{Y*} %{d*} %{m*} %{f*} %{a}\
+ %{g} %{O} %{W*} %{w} %{pedantic} %{ansi} %{traditional}\
+ %{v:-version} %{gg:-symout %g.sym} %{pg:-p} %{p} %{xref}\
+ %{S:%{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %{R} %{j} %{J} %{h} %{d2} %a %{gg:-G %g.sym}\
+ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %{!pipe:%g.s}\n }"},
+ {".s",
+ "%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
+ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o} %i\n }"},
+ {".S",
+ "cpp %{nostdinc} %{C} %{v} %{D*} %{U*} %{I*} %{i*} %{M*} %{trigraphs} \
+ -undef -D__GNUC__ -$ %p %P\
+ %c %{O:-D__OPTIMIZE__} %{traditional} %{pedantic}\
+ %{Wcomment*} %{Wtrigraphs} %{Wall} %C\
+ %i %{!M*:%{!E:%{!pipe:%g.s}}}%{E:%{o*}}%{M*:%{o*}} |\n\
+ %{!M*:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a \
+ %{c:%{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%b.o}\
+ %{!pipe:%g.s}\n }}}"},
+ /* Mark end of table */
+ {0, 0}
+};
+
+#ifdef USE_COLLECT
+/* C++: Here is the spec for collecting global ctor and dtor
+ requirements. */
+char *collect_spec =
+ "%{!c:%{!M*:%{!E:%{!S:collect -o %g.s %g.R\n\
+as %g.s -o %g.O\n\
+ld %{o*} %g.R %g.O\n\
+}}}}";
+
+/* Here is the spec for running the linker, after compiling all files. */
+char *link_spec = "%{!c:%{!M*:%{!E:%{!S:ld -r -o %g.R %l\
+ %{A} %{d} %{e*} %{N} %{n} %{r} %{s} %{S} %{T*} %{t} %{u*} %{X} %{x} %{z}\
+ %{y*} %{!nostdlib:%S} \
+ %{L*} %o %{!nostdlib:-lg++ %L -lgnulib}\n }}}}";
+#else
+/* Here is the spec for running the linker, after compiling all files. */
+char *link_spec = "%{!c:%{!M*:%{!E:%{!S:ld %{o*} %l\
+ %{A} %{d} %{e*} %{N} %{n} %{r} %{s} %{S} %{T*} %{t} %{u*} %{X} %{x} %{z}\
+ %{y*} %{!nostdlib:%S} \
+ %{L*} %o %{!nostdlib:-lg++ %L -lgnulib}\n }}}}";
+#endif
+\f
+/* Accumulate a command (program name and args), and run it. */
+
+/* Vector of pointers to arguments in the current line of specifications. */
+
+char **argbuf;
+
+/* Number of elements allocated in argbuf. */
+
+int argbuf_length;
+
+/* Number of elements in argbuf currently in use (containing args). */
+
+int argbuf_index;
+
+/* Number of commands executed so far. */
+
+int execution_count;
+
+/* Flag indicating whether we should print the command and arguments */
+
+unsigned char vflag;
+
+/* Name with which this program was invoked. */
+
+char *programname;
+
+/* User-specified -B prefix to attach to command names,
+ or 0 if none specified. */
+
+char *user_exec_prefix = 0;
+int user_exec_prefix_used = 0;
+
+/* Environment-specified prefix to attach to command names,
+ or 0 if none specified. */
+
+char *env_exec_prefix = 0;
+
+/* Suffix to attach to directories searched for commands. */
+
+char *machine_suffix = 0;
+
+/* Default prefixes to attach to command names. */
+
+#ifndef STANDARD_EXEC_PREFIX
+#define STANDARD_EXEC_PREFIX "/usr/local/lib/gcc-"
+#endif /* !defined STANDARD_EXEC_PREFIX */
+
+char *standard_exec_prefix = STANDARD_EXEC_PREFIX;
+char *standard_exec_prefix_1 = "/usr/lib/gcc-";
+
+#ifndef STANDARD_STARTFILE_PREFIX
+#define STANDARD_STARTFILE_PREFIX "/usr/local/lib/"
+#endif /* !defined STANDARD_STARTFILE_PREFIX */
+
+char *standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
+char *standard_startfile_prefix_1 = "/lib/";
+char *standard_startfile_prefix_2 = "/usr/lib/";
+
+/* Clear out the vector of arguments (after a command is executed). */
+
+void
+clear_args ()
+{
+ argbuf_index = 0;
+}
+
+/* Add one argument to the vector at the end.
+ This is done when a space is seen or at the end of the line.
+ If DELETE_ALWAYS is nonzero, the arg is a filename
+ and the file should be deleted eventually.
+ If DELETE_FAILURE is nonzero, the arg is a filename
+ and the file should be deleted if this compilation fails. */
+
+void
+store_arg (arg, delete_always, delete_failure)
+ char *arg;
+ int delete_always, delete_failure;
+{
+ if (argbuf_index + 1 == argbuf_length)
+ {
+ argbuf = (char **) realloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
+ }
+
+ argbuf[argbuf_index++] = arg;
+ argbuf[argbuf_index] = 0;
+
+ if (delete_always || delete_failure)
+ record_temp_file (arg, delete_always, delete_failure);
+}
+\f
+/* Record the names of temporary files we tell compilers to write,
+ and delete them at the end of the run. */
+
+/* This is the common prefix we use to make temp file names.
+ It is chosen once for each run of this program.
+ It is substituted into a spec by %g.
+ Thus, all temp file names contain this prefix.
+ In practice, all temp file names start with this prefix.
+
+ This prefix comes from the envvar TMPDIR if it is defined;
+ otherwise, in /tmp. */
+
+char *temp_filename;
+
+/* Length of the prefix. */
+
+int temp_filename_length;
+
+/* Define the list of temporary files to delete. */
+
+struct temp_file
+{
+ char *name;
+ struct temp_file *next;
+};
+
+/* Queue of files to delete on success or failure of compilation. */
+struct temp_file *always_delete_queue;
+/* Queue of files to delete on failure of compilation. */
+struct temp_file *failure_delete_queue;
+
+/* Record FILENAME as a file to be deleted automatically.
+ ALWAYS_DELETE nonzero means delete it if all compilation succeeds;
+ otherwise delete it in any case.
+ FAIL_DELETE nonzero means delete it if a compilation step fails;
+ otherwise delete it in any case. */
+
+void
+record_temp_file (filename, always_delete, fail_delete)
+ char *filename;
+ int always_delete;
+ int fail_delete;
+{
+ register char *name;
+ name = (char *) xmalloc (strlen (filename) + 1);
+ strcpy (name, filename);
+
+ if (always_delete)
+ {
+ register struct temp_file *temp;
+ for (temp = always_delete_queue; temp; temp = temp->next)
+ if (! strcmp (name, temp->name))
+ goto already1;
+ temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
+ temp->next = always_delete_queue;
+ temp->name = name;
+ always_delete_queue = temp;
+ already1:;
+ }
+
+ if (fail_delete)
+ {
+ register struct temp_file *temp;
+ for (temp = failure_delete_queue; temp; temp = temp->next)
+ if (! strcmp (name, temp->name))
+ goto already2;
+ temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
+ temp->next = failure_delete_queue;
+ temp->name = name;
+ failure_delete_queue = temp;
+ already2:;
+ }
+}
+
+/* Delete all the temporary files whose names we previously recorded. */
+
+void
+delete_temp_files ()
+{
+ register struct temp_file *temp;
+
+ for (temp = always_delete_queue; temp; temp = temp->next)
+ {
+#ifdef DEBUG
+ int i;
+ printf ("Delete %s? (y or n) ", temp->name);
+ fflush (stdout);
+ i = getchar ();
+ if (i != '\n')
+ while (getchar () != '\n') ;
+ if (i == 'y' || i == 'Y')
+#endif /* DEBUG */
+ {
+ if (unlink (temp->name) < 0)
+ if (vflag)
+ perror_with_name (temp->name);
+ }
+ }
+
+ always_delete_queue = 0;
+}
+
+/* Delete all the files to be deleted on error. */
+
+void
+delete_failure_queue ()
+{
+ register struct temp_file *temp;
+
+ for (temp = failure_delete_queue; temp; temp = temp->next)
+ {
+#ifdef DEBUG
+ int i;
+ printf ("Delete %s? (y or n) ", temp->name);
+ fflush (stdout);
+ i = getchar ();
+ if (i != '\n')
+ while (getchar () != '\n') ;
+ if (i == 'y' || i == 'Y')
+#endif /* DEBUG */
+ {
+ if (unlink (temp->name) < 0)
+ if (vflag)
+ perror_with_name (temp->name);
+ }
+ }
+}
+
+void
+clear_failure_queue ()
+{
+ failure_delete_queue = 0;
+}
+
+/* Compute a string to use as the base of all temporary file names.
+ It is substituted for %g. */
+
+void
+choose_temp_base ()
+{
+ extern char *getenv ();
+ char *base = getenv ("TMPDIR");
+ int len;
+
+ if (base == (char *)0)
+ base = "/tmp/";
+
+ len = strlen (base);
+ temp_filename = (char *) xmalloc (len + sizeof("/ccXXXXXX"));
+ strcpy (temp_filename, base);
+ if (len > 0 && temp_filename[len-1] != '/')
+ temp_filename[len++] = '/';
+ strcpy (temp_filename + len, "ccXXXXXX");
+
+ mktemp (temp_filename);
+ temp_filename_length = strlen (temp_filename);
+}
+\f
+/* Search for an execute file through our search path.
+ Return 0 if not found, otherwise return its name, allocated with malloc. */
+
+static char *
+find_exec_file (prog)
+ char *prog;
+{
+ int win = 0;
+ char *temp;
+ int size;
+
+ size = strlen (standard_exec_prefix);
+ if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size)
+ size = strlen (user_exec_prefix);
+ if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size)
+ size = strlen (env_exec_prefix);
+ if (strlen (standard_exec_prefix_1) > size)
+ size = strlen (standard_exec_prefix_1);
+ size += strlen (prog) + 1;
+ if (machine_suffix)
+ size += strlen (machine_suffix) + 1;
+ temp = (char *) xmalloc (size);
+
+ /* Determine the filename to execute. */
+
+ if (user_exec_prefix)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, user_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, user_exec_prefix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ user_exec_prefix_used |= win;
+ }
+
+ if (!win && env_exec_prefix)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, env_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, env_exec_prefix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_exec_prefix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_exec_prefix_1);
+ strcat (temp, machine_suffix);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_exec_prefix_1);
+ strcat (temp, prog);
+ win = (access (temp, X_OK) == 0);
+ }
+ }
+
+ if (win)
+ return temp;
+ else
+ return 0;
+}
+\f
+/* stdin file number. */
+#define STDIN_FILE_NO 0
+
+/* stdout file number. */
+#define STDOUT_FILE_NO 1
+
+/* value of `pipe': port index for reading. */
+#define READ_PORT 0
+
+/* value of `pipe': port index for writing. */
+#define WRITE_PORT 1
+
+/* Pipe waiting from last process, to be used as input for the next one.
+ Value is STDIN_FILE_NO if no pipe is waiting
+ (i.e. the next command is the first of a group). */
+
+int last_pipe_input;
+
+/* Fork one piped subcommand. FUNC is the system call to use
+ (either execv or execvp). ARGV is the arg vector to use.
+ NOT_LAST is nonzero if this is not the last subcommand
+ (i.e. its output should be piped to the next one.) */
+
+static int
+pexecute (func, program, argv, not_last)
+ char *program;
+ int (*func)();
+ char *argv[];
+ int not_last;
+{
+ int pid;
+ int pdes[2];
+ int input_desc = last_pipe_input;
+ int output_desc = STDOUT_FILE_NO;
+
+ /* If this isn't the last process, make a pipe for its output,
+ and record it as waiting to be the input to the next process. */
+
+ if (not_last)
+ {
+ if (pipe (pdes) < 0)
+ pfatal_with_name ("pipe");
+ output_desc = pdes[WRITE_PORT];
+ last_pipe_input = pdes[READ_PORT];
+ }
+ else
+ last_pipe_input = STDIN_FILE_NO;
+
+ pid = vfork ();
+
+ switch (pid)
+ {
+ case -1:
+ pfatal_with_name ("vfork");
+ break;
+
+ case 0: /* child */
+ /* Move the input and output pipes into place, if nec. */
+ if (input_desc != STDIN_FILE_NO)
+ {
+ close (STDIN_FILE_NO);
+ dup (input_desc);
+ close (input_desc);
+ }
+ if (output_desc != STDOUT_FILE_NO)
+ {
+ close (STDOUT_FILE_NO);
+ dup (output_desc);
+ close (output_desc);
+ }
+
+ /* Close the parent's descs that aren't wanted here. */
+ if (last_pipe_input != STDIN_FILE_NO)
+ close (last_pipe_input);
+
+ /* Exec the program. */
+ (*func) (program, argv);
+ perror_exec (program);
+ exit (-1);
+ /* NOTREACHED */
+
+ default:
+ /* In the parent, after forking.
+ Close the descriptors that we made for this child. */
+ if (input_desc != STDIN_FILE_NO)
+ close (input_desc);
+ if (output_desc != STDOUT_FILE_NO)
+ close (output_desc);
+
+ /* Return child's process number. */
+ return pid;
+ }
+}
+\f
+/* Execute the command specified by the arguments on the current line of spec.
+ When using pipes, this includes several piped-together commands
+ with `|' between them.
+
+ Return 0 if successful, -1 if failed. */
+
+int
+execute ()
+{
+ int i;
+ int n_commands; /* # of command. */
+ char *string;
+ struct command
+ {
+ char *prog; /* program name. */
+ char **argv; /* vector of args. */
+ int pid; /* pid of process for this command. */
+ };
+
+ struct command *commands; /* each command buffer with above info. */
+
+ /* Count # of piped commands. */
+ for (n_commands = 1, i = 0; i < argbuf_index; i++)
+ if (strcmp (argbuf[i], "|") == 0)
+ n_commands++;
+
+ /* Get storage for each command. */
+ commands
+ = (struct command *) alloca (n_commands * sizeof (struct command));
+
+ /* Split argbuf into its separate piped processes,
+ and record info about each one.
+ Also search for the programs that are to be run. */
+
+ commands[0].prog = argbuf[0]; /* first command. */
+ commands[0].argv = &argbuf[0];
+ string = find_exec_file (commands[0].prog);
+ if (string)
+ commands[0].argv[0] = string;
+
+ for (n_commands = 1, i = 0; i < argbuf_index; i++)
+ if (strcmp (argbuf[i], "|") == 0)
+ { /* each command. */
+ argbuf[i] = 0; /* termination of command args. */
+ commands[n_commands].prog = argbuf[i + 1];
+ commands[n_commands].argv = &argbuf[i + 1];
+ string = find_exec_file (commands[n_commands].prog);
+ if (string)
+ commands[n_commands].argv[0] = string;
+ n_commands++;
+ }
+
+ argbuf[argbuf_index] = 0;
+
+ /* If -v, print what we are about to do, and maybe query. */
+
+ if (vflag)
+ {
+ /* Print each piped command as a separate line. */
+ for (i = 0; i < n_commands ; i++)
+ {
+ char **j;
+
+ for (j = commands[i].argv; *j; j++)
+ fprintf (stderr, " %s", *j);
+
+ /* Print a pipe symbol after all but the last command. */
+ if (i + 1 != n_commands)
+ fprintf (stderr, " |");
+ fprintf (stderr, "\n");
+ }
+ fflush (stderr);
+#ifdef DEBUG
+ fprintf (stderr, "\nGo ahead? (y or n) ");
+ fflush (stderr);
+ j = getchar ();
+ if (j != '\n')
+ while (getchar () != '\n') ;
+ if (j != 'y' && j != 'Y')
+ return 0;
+#endif /* DEBUG */
+ }
+
+ /* Run each piped subprocess. */
+
+ last_pipe_input = STDIN_FILE_NO;
+ for (i = 0; i < n_commands; i++)
+ {
+ extern int execv(), execvp();
+ char *string = commands[i].argv[0];
+
+ commands[i].pid = pexecute ((string != commands[i].prog ? execv : execvp),
+ string, commands[i].argv,
+ i + 1 < n_commands);
+
+ if (string != commands[i].prog)
+ free (string);
+ }
+
+ execution_count++;
+
+ /* Wait for all the subprocesses to finish.
+ We don't care what order they finish in;
+ we know that N_COMMANDS waits will get them all. */
+
+ {
+ int ret_code = 0;
+
+ for (i = 0; i < n_commands; i++)
+ {
+ int status;
+ int pid;
+ char *prog;
+
+ pid = wait (&status);
+ if (pid < 0)
+ abort ();
+
+ if (status != 0)
+ {
+ int j;
+ for (j = 0; j < n_commands; j++)
+ if (commands[j].pid == pid)
+ prog = commands[j].prog;
+
+ if ((status & 0x7F) != 0)
+ fatal ("Program %s got fatal signal %d.", prog, (status & 0x7F));
+ if (((status & 0xFF00) >> 8) >= MIN_FATAL_STATUS)
+ ret_code = -1;
+ }
+ }
+ return ret_code;
+ }
+}
+\f
+/* Find all the switches given to us
+ and make a vector describing them.
+
+ The elements of the vector a strings, one per switch given.
+ If a switch uses the following argument, then the `part1' field
+ is the switch itself and the `part2' field is the following argument.
+ The `valid' field is nonzero if any spec has looked at this switch;
+ if it remains zero at the end of the run, it must be meaningless.
+
+ `prefix' is the prefix of this switch which makes it
+ recognizable as a switch. This is almost always "-". When
+ it is NULL, it means that the prefix to this switch is part
+ `part1' instead. */
+
+struct switchstr
+{
+ char *prefix;
+ char *part1;
+ char *part2;
+ int valid;
+};
+
+struct switchstr *switches;
+
+int n_switches;
+
+/* Also a vector of input files specified. */
+
+char **infiles;
+
+int n_infiles;
+
+/* And a vector of corresponding output files is made up later. */
+
+char **outfiles;
+
+/* Create the vector `switches' and its contents.
+ Store its length in `n_switches'. */
+
+void
+process_command (argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *getenv ();
+ register int i;
+ n_switches = 0;
+ n_infiles = 0;
+
+ env_exec_prefix = getenv ("GCC_EXEC_PREFIX");
+
+ /* Scan argv twice. Here, the first time, just count how many switches
+ there will be in their vector, and how many input files in theirs.
+ Here we also parse the switches that cc itself uses (e.g. -v). */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1] != 'l')
+ {
+ register char *p = &argv[i][1];
+ register int c = *p;
+
+ switch (c)
+ {
+ case 'b':
+ machine_suffix = p + 1;
+ break;
+
+ case 'B':
+ user_exec_prefix = p + 1;
+ break;
+
+ case 'v': /* Print our subcommands and print versions. */
+ vflag++;
+ n_switches++;
+ break;
+
+ default:
+ n_switches++;
+
+ if (SWITCH_TAKES_ARG (c) && p[1] == 0)
+ i++;
+ else if (WORD_SWITCH_TAKES_ARG (p))
+ i++;
+ }
+ }
+ else if (argv[i][0] == '+')
+ ;
+ else
+ n_infiles++;
+ }
+
+ /* Then create the space for the vectors and scan again. */
+
+ switches = ((struct switchstr *)
+ xmalloc ((n_switches + 1) * sizeof (struct switchstr)));
+ infiles = (char **) xmalloc ((n_infiles + 1) * sizeof (char *));
+ n_switches = 0;
+ n_infiles = 0;
+
+ /* This, time, copy the text of each switch and store a pointer
+ to the copy in the vector of switches.
+ Store all the infiles in their vector. */
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-' && argv[i][1] != 'l')
+ {
+ register char *p = &argv[i][1];
+ register int c = *p;
+
+ if (c == 'B' || c == 'b')
+ continue;
+ switches[n_switches].prefix = "-";
+ switches[n_switches].part1 = p;
+ if ((SWITCH_TAKES_ARG (c) && p[1] == 0)
+ || WORD_SWITCH_TAKES_ARG (p))
+ switches[n_switches].part2 = argv[++i];
+ else
+ switches[n_switches].part2 = 0;
+ switches[n_switches].valid = 0;
+ n_switches++;
+ }
+ else if (argv[i][0] == '+')
+ {
+ switches[n_switches].prefix = "";
+ switches[n_switches].part1 = argv[i];
+ switches[n_switches].part2 = 0;
+ switches[n_switches].valid = 0;
+ n_switches++;
+ }
+ else
+ infiles[n_infiles++] = argv[i];
+ }
+
+ switches[n_switches].part1 = 0;
+ infiles[n_infiles] = 0;
+}
+\f
+/* Process a spec string, accumulating and running commands. */
+
+/* These variables describe the input file name.
+ input_file_number is the index on outfiles of this file,
+ so that the output file name can be stored for later use by %o.
+ input_basename is the start of the part of the input file
+ sans all directory names, and basename_length is the number
+ of characters starting there excluding the suffix .c or whatever. */
+
+char *input_filename;
+int input_file_number;
+int input_filename_length;
+int basename_length;
+char *input_basename;
+
+/* These are variables used within do_spec and do_spec_1. */
+
+/* Nonzero if an arg has been started and not yet terminated
+ (with space, tab or newline). */
+int arg_going;
+
+/* Nonzero means %d or %g has been seen; the next arg to be terminated
+ is a temporary file name. */
+int delete_this_arg;
+
+/* Nonzero means %w has been seen; the next arg to be terminated
+ is the output file name of this compilation. */
+int this_is_output_file;
+
+/* Nonzero means %s has been seen; the next arg to be terminated
+ is the name of a library file and we should try the standard
+ search dirs for it. */
+int this_is_library_file;
+
+/* Process the spec SPEC and run the commands specified therein.
+ Returns 0 if the spec is successfully processed; -1 if failed. */
+
+int
+do_spec (spec)
+ char *spec;
+{
+ int value;
+
+ clear_args ();
+ arg_going = 0;
+ delete_this_arg = 0;
+ this_is_output_file = 0;
+ this_is_library_file = 0;
+
+ value = do_spec_1 (spec, 0);
+
+ /* Force out any unfinished command.
+ If -pipe, this forces out the last command if it ended in `|'. */
+ if (value == 0)
+ {
+ if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
+ argbuf_index--;
+
+ if (argbuf_index > 0)
+ value = execute ();
+ }
+
+ return value;
+}
+
+/* Process the sub-spec SPEC as a portion of a larger spec.
+ This is like processing a whole spec except that we do
+ not initialize at the beginning and we do not supply a
+ newline by default at the end.
+ INSWITCH nonzero means don't process %-sequences in SPEC;
+ in this case, % is treated as an ordinary character.
+ This is used while substituting switches.
+ INSWITCH nonzero also causes SPC not to terminate an argument.
+
+ Value is zero unless a line was finished
+ and the command on that line reported an error. */
+
+int
+do_spec_1 (spec, inswitch)
+ char *spec;
+ int inswitch;
+{
+ register char *p = spec;
+ register int c;
+ char *string;
+
+ while (c = *p++)
+ /* If substituting a switch, treat all chars like letters.
+ Otherwise, NL, SPC, TAB and % are special. */
+ switch (inswitch ? 'a' : c)
+ {
+ case '\n':
+ /* End of line: finish any pending argument,
+ then run the pending command if one has been started. */
+ if (arg_going)
+ {
+ obstack_1grow (&obstack, 0);
+ string = obstack_finish (&obstack);
+ if (this_is_library_file)
+ string = find_file (string);
+ store_arg (string, delete_this_arg, this_is_output_file);
+ if (this_is_output_file)
+ outfiles[input_file_number] = string;
+ }
+ arg_going = 0;
+
+ if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
+ {
+ int i;
+ for (i = 0; i < n_switches; i++)
+ if (!strcmp (switches[i].part1, "pipe"))
+ break;
+
+ /* A `|' before the newline means use a pipe here,
+ but only if -pipe was specified.
+ Otherwise, execute now and don't pass the `|' as an arg. */
+ if (i < n_switches)
+ {
+ switches[i].valid = 1;
+ break;
+ }
+ else
+ argbuf_index--;
+ }
+
+ if (argbuf_index > 0)
+ {
+ int value = execute ();
+ if (value)
+ return value;
+ }
+ /* Reinitialize for a new command, and for a new argument. */
+ clear_args ();
+ arg_going = 0;
+ delete_this_arg = 0;
+ this_is_output_file = 0;
+ this_is_library_file = 0;
+ break;
+
+ case '|':
+ /* End any pending argument. */
+ if (arg_going)
+ {
+ obstack_1grow (&obstack, 0);
+ string = obstack_finish (&obstack);
+ if (this_is_library_file)
+ string = find_file (string);
+ store_arg (string, delete_this_arg, this_is_output_file);
+ if (this_is_output_file)
+ outfiles[input_file_number] = string;
+ }
+
+ /* Use pipe */
+ obstack_1grow (&obstack, c);
+ arg_going = 1;
+ break;
+
+ case '\t':
+ case ' ':
+ /* Space or tab ends an argument if one is pending. */
+ if (arg_going)
+ {
+ obstack_1grow (&obstack, 0);
+ string = obstack_finish (&obstack);
+ if (this_is_library_file)
+ string = find_file (string);
+ store_arg (string, delete_this_arg, this_is_output_file);
+ if (this_is_output_file)
+ outfiles[input_file_number] = string;
+ }
+ /* Reinitialize for a new argument. */
+ arg_going = 0;
+ delete_this_arg = 0;
+ this_is_output_file = 0;
+ this_is_library_file = 0;
+ break;
+
+ case '%':
+ switch (c = *p++)
+ {
+ case 0:
+ fatal ("Invalid specification! Bug in cc.");
+
+ case 'b':
+ obstack_grow (&obstack, input_basename, basename_length);
+ arg_going = 1;
+ break;
+
+ case 'd':
+ delete_this_arg = 2;
+ break;
+
+ case 'e':
+ /* {...:%efoo} means report an error with `foo' as error message
+ and don't execute any more commands for this file. */
+ {
+ char *q = p;
+ char *buf;
+ while (*p != 0 && *p != '\n') p++;
+ buf = (char *) alloca (p - q + 1);
+ strncpy (buf, q, p - q);
+ error ("%s", buf);
+ return -1;
+ }
+ break;
+
+ case 'g':
+ obstack_grow (&obstack, temp_filename, temp_filename_length);
+ delete_this_arg = 1;
+ arg_going = 1;
+ break;
+
+ case 'i':
+ obstack_grow (&obstack, input_filename, input_filename_length);
+ arg_going = 1;
+ break;
+
+ case 'o':
+ {
+ register int f;
+ for (f = 0; f < n_infiles; f++)
+ store_arg (outfiles[f], 0, 0);
+ }
+ break;
+
+ case 's':
+ this_is_library_file = 1;
+ break;
+
+ case 'w':
+ this_is_output_file = 1;
+ break;
+
+ case '{':
+ p = handle_braces (p);
+ if (p == 0)
+ return -1;
+ break;
+
+ case '%':
+ obstack_1grow (&obstack, '%');
+ break;
+
+/*** The rest just process a certain constant string as a spec. */
+
+ case '1':
+ do_spec_1 (CC1_SPEC, 0);
+ break;
+
+ case 'a':
+ do_spec_1 (ASM_SPEC, 0);
+ break;
+
+ case 'c':
+ do_spec_1 (SIGNED_CHAR_SPEC, 0);
+ break;
+
+ case 'C':
+ do_spec_1 (CPP_SPEC, 0);
+ break;
+
+ case 'l':
+ do_spec_1 (LINK_SPEC, 0);
+ break;
+
+ case 'L':
+ do_spec_1 (LIB_SPEC, 0);
+ break;
+
+ case 'p':
+ do_spec_1 (CPP_PREDEFINES, 0);
+ break;
+
+ case 'P':
+ {
+ char *x = (char *) alloca (strlen (CPP_PREDEFINES) * 2 + 1);
+ char *buf = x;
+ char *y = CPP_PREDEFINES;
+
+ /* Copy all of CPP_PREDEFINES into BUF,
+ but put __ after every -D and at the end of each arg, */
+ while (1)
+ {
+ if (! strncmp (y, "-D", 2))
+ {
+ *x++ = '-';
+ *x++ = 'D';
+ *x++ = '_';
+ *x++ = '_';
+ y += 2;
+ }
+ else if (*y == ' ' || *y == 0)
+ {
+ *x++ = '_';
+ *x++ = '_';
+ if (*y == 0)
+ break;
+ else
+ *x++ = *y++;
+ }
+ else
+ *x++ = *y++;
+ }
+ *x = 0;
+
+ do_spec_1 (buf, 0);
+ }
+ break;
+
+ case 'S':
+ do_spec_1 (STARTFILE_SPEC, 0);
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ default:
+ /* Ordinary character: put it into the current argument. */
+ obstack_1grow (&obstack, c);
+ arg_going = 1;
+ }
+
+ return 0; /* End of string */
+}
+
+/* Return 0 if we call do_spec_1 and that returns -1. */
+
+char *
+handle_braces (p)
+ register char *p;
+{
+ register char *q;
+ char *filter;
+ int pipe = 0;
+ int negate = 0;
+
+ if (*p == '|')
+ /* A `|' after the open-brace means,
+ if the test fails, output a single minus sign rather than nothing.
+ This is used in %{|!pipe:...}. */
+ pipe = 1, ++p;
+
+ if (*p == '!')
+ /* A `!' after the open-brace negates the condition:
+ succeed if the specified switch is not present. */
+ negate = 1, ++p;
+
+ filter = p;
+ while (*p != ':' && *p != '}') p++;
+ if (*p != '}')
+ {
+ register int count = 1;
+ q = p + 1;
+ while (count > 0)
+ {
+ if (*q == '{')
+ count++;
+ else if (*q == '}')
+ count--;
+ else if (*q == 0)
+ abort ();
+ q++;
+ }
+ }
+ else
+ q = p + 1;
+
+ if (p[-1] == '*' && p[0] == '}')
+ {
+ /* Substitute all matching switches as separate args. */
+ register int i;
+ --p;
+ for (i = 0; i < n_switches; i++)
+ if (!strncmp (switches[i].part1, filter, p - filter))
+ give_switch (i);
+ }
+ else
+ {
+ /* Test for presence of the specified switch. */
+ register int i;
+ int present = 0;
+
+ /* If name specified ends in *, as in {x*:...},
+ check for presence of any switch name starting with x. */
+ if (p[-1] == '*')
+ {
+ for (i = 0; i < n_switches; i++)
+ {
+ if (!strncmp (switches[i].part1, filter, p - filter - 1))
+ {
+ switches[i].valid = 1;
+ present = 1;
+ }
+ }
+ }
+ /* Otherwise, check for presence of exact name specified. */
+ else
+ {
+ for (i = 0; i < n_switches; i++)
+ {
+ if (!strncmp (switches[i].part1, filter, p - filter)
+ && switches[i].part1[p - filter] == 0)
+ {
+ switches[i].valid = 1;
+ present = 1;
+ break;
+ }
+ }
+ }
+
+ /* If it is as desired (present for %{s...}, absent for %{-s...})
+ then substitute either the switch or the specified
+ conditional text. */
+ if (present != negate)
+ {
+ if (*p == '}')
+ {
+ give_switch (i);
+ }
+ else
+ {
+ if (do_spec_1 (save_string (p + 1, q - p - 2), 0) < 0)
+ return 0;
+ }
+ }
+ else if (pipe)
+ {
+ /* Here if a %{|...} conditional fails: output a minus sign,
+ which means "standard output" or "standard input". */
+ do_spec_1 ("-", 0);
+ }
+ }
+
+ return q;
+}
+
+/* Pass a switch to the current accumulating command
+ in the same form that we received it.
+ SWITCHNUM identifies the switch; it is an index into
+ the vector of switches gcc received, which is `switches'.
+ This cannot fail since it never finishes a command line. */
+
+give_switch (switchnum)
+ int switchnum;
+{
+ do_spec_1 (switches[switchnum].prefix, 1);
+ do_spec_1 (switches[switchnum].part1, 1);
+ do_spec_1 (" ", 0);
+ if (switches[switchnum].part2 != 0)
+ {
+ do_spec_1 (switches[switchnum].part2, 1);
+ do_spec_1 (" ", 0);
+ }
+ switches[switchnum].valid = 1;
+}
+\f
+/* Search for a file named NAME trying various prefixes including the
+ user's -B prefix and some standard ones.
+ Return the absolute pathname found. If nothing is found, return NAME. */
+
+char *
+find_file (name)
+ char *name;
+{
+ int size;
+ char *temp;
+ int win = 0;
+
+ /* Compute maximum size of NAME plus any prefix we will try. */
+
+ size = strlen (standard_exec_prefix);
+ if (user_exec_prefix != 0 && strlen (user_exec_prefix) > size)
+ size = strlen (user_exec_prefix);
+ if (env_exec_prefix != 0 && strlen (env_exec_prefix) > size)
+ size = strlen (env_exec_prefix);
+ if (strlen (standard_exec_prefix) > size)
+ size = strlen (standard_exec_prefix);
+ if (strlen (standard_exec_prefix_1) > size)
+ size = strlen (standard_exec_prefix_1);
+ if (strlen (standard_startfile_prefix) > size)
+ size = strlen (standard_startfile_prefix);
+ if (strlen (standard_startfile_prefix_1) > size)
+ size = strlen (standard_startfile_prefix_1);
+ if (strlen (standard_startfile_prefix_2) > size)
+ size = strlen (standard_startfile_prefix_2);
+ if (machine_suffix)
+ size += strlen (machine_suffix) + 1;
+ size += strlen (name) + 1;
+
+ temp = (char *) alloca (size);
+
+ if (user_exec_prefix)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, user_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, user_exec_prefix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win && env_exec_prefix)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, env_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, env_exec_prefix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_exec_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_exec_prefix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_exec_prefix_1);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_exec_prefix_1);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_startfile_prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_startfile_prefix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_startfile_prefix_1);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_startfile_prefix_1);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, standard_startfile_prefix_2);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, standard_startfile_prefix_2);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (!win)
+ {
+ if (machine_suffix)
+ {
+ strcpy (temp, "./");
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ if (!win)
+ {
+ strcpy (temp, "./");
+ strcat (temp, name);
+ win = (access (temp, R_OK) == 0);
+ }
+ }
+
+ if (win)
+ return save_string (temp, strlen (temp));
+ return name;
+}
+\f
+/* On fatal signals, delete all the temporary files. */
+
+void
+fatal_error (signum)
+ int signum;
+{
+ signal (signum, SIG_DFL);
+ delete_failure_queue ();
+ delete_temp_files ();
+ /* Get the same signal again, this time not handled,
+ so its normal effect occurs. */
+ kill (getpid (), signum);
+}
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ int value;
+ int error_count = 0;
+ int linker_was_run = 0;
+ char *explicit_link_files;
+
+ programname = argv[0];
+
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_error);
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_error);
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_error);
+
+ argbuf_length = 10;
+ argbuf = (char **) xmalloc (argbuf_length * sizeof (char *));
+
+ obstack_init (&obstack);
+
+ choose_temp_base ();
+
+ /* Make a table of what switches there are (switches, n_switches).
+ Make a table of specified input files (infiles, n_infiles). */
+
+ process_command (argc, argv);
+
+ if (vflag)
+ {
+ extern char *version_string;
+ fprintf (stderr, "g++ version %s\n", version_string);
+ if (n_infiles == 0)
+ exit (0);
+ }
+
+ if (n_infiles == 0)
+ fatal ("No input files specified.");
+
+ /* Make a place to record the compiler output file names
+ that correspond to the input files. */
+
+ outfiles = (char **) xmalloc (n_infiles * sizeof (char *));
+ bzero (outfiles, n_infiles * sizeof (char *));
+
+ /* Record which files were specified explicitly as link input. */
+
+ explicit_link_files = (char *) xmalloc (n_infiles);
+ bzero (explicit_link_files, n_infiles);
+
+ for (i = 0; i < n_infiles; i++)
+ {
+ register struct compiler *cp;
+ int this_file_error = 0;
+
+ /* Tell do_spec what to substitute for %i. */
+
+ input_filename = infiles[i];
+ input_filename_length = strlen (input_filename);
+ input_file_number = i;
+
+ /* Use the same thing in %o, unless cp->spec says otherwise. */
+
+ outfiles[i] = input_filename;
+
+ /* Figure out which compiler from the file's suffix. */
+
+ for (cp = compilers; cp->spec; cp++)
+ {
+ if (strlen (cp->suffix) < input_filename_length
+ && !strcmp (cp->suffix,
+ infiles[i] + input_filename_length
+ - strlen (cp->suffix)))
+ {
+ /* Ok, we found an applicable compiler. Run its spec. */
+ /* First say how much of input_filename to substitute for %b */
+ register char *p;
+
+ input_basename = input_filename;
+ for (p = input_filename; *p; p++)
+ if (*p == '/')
+ input_basename = p + 1;
+ basename_length = (input_filename_length - strlen (cp->suffix)
+ - (input_basename - input_filename));
+ value = do_spec (cp->spec);
+ if (value < 0)
+ this_file_error = 1;
+ else
+ if (user_exec_prefix != 0
+ && user_exec_prefix_used == 0)
+ fprintf (stderr, "`-B%s' not used by compiler\n", user_exec_prefix);
+ break;
+ }
+ }
+
+ /* If this file's name does not contain a recognized suffix,
+ record it as explicit linker input. */
+
+ if (! cp->spec)
+ explicit_link_files[i] = 1;
+
+ /* Clear the delete-on-failure queue, deleting the files in it
+ if this compilation failed. */
+
+ if (this_file_error)
+ {
+ delete_failure_queue ();
+ error_count++;
+ }
+ /* If this compilation succeeded, don't delete those files later. */
+ clear_failure_queue ();
+ }
+
+ /* Run ld to link all the compiler output files. */
+
+ if (error_count == 0)
+ {
+ int tmp = execution_count;
+ value = do_spec (link_spec);
+ if (value < 0)
+ error_count = 1;
+ linker_was_run = (tmp != execution_count);
+ }
+
+#ifdef USE_COLLECT
+ /* C++: now collect all the requirements for
+ calling global constructors and destructors,
+ and write them to a file. We will link this file
+ in when we run. */
+ if (linker_was_run && ! error_count)
+ {
+ int tmp = execution_count;
+ value = do_spec (collect_spec);
+ if (value < 0)
+ error_count = 1;
+ linker_was_run &= (tmp != execution_count);
+ }
+#endif
+
+ /* If options said don't run linker,
+ complain about input files to be given to the linker. */
+
+ if (! linker_was_run && error_count == 0)
+ for (i = 0; i < n_infiles; i++)
+ if (explicit_link_files[i])
+ error ("%s: linker input file unused since linking not done",
+ outfiles[i]);
+
+ /* Set the `valid' bits for switches that match anything in any spec. */
+
+ validate_all_switches ();
+
+ /* Warn about any switches that no pass was interested in. */
+
+ for (i = 0; i < n_switches; i++)
+ if (! switches[i].valid)
+ error ("unrecognized option `%s%s'",
+ switches[i].prefix, switches[i].part1);
+
+ /* Delete some or all of the temporary files we made. */
+
+ if (error_count)
+ delete_failure_queue ();
+ delete_temp_files ();
+
+ exit (error_count);
+}
+\f
+xmalloc (size)
+ int size;
+{
+ register int value = malloc (size);
+ if (value == 0)
+ fatal ("Virtual memory full.");
+ return value;
+}
+
+xrealloc (ptr, size)
+ int ptr, size;
+{
+ register int value = realloc (ptr, size);
+ if (value == 0)
+ fatal ("Virtual memory full.");
+ return value;
+}
+
+/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ *(result + len1 + len2 + len3) = 0;
+
+ return result;
+}
+
+char *
+save_string (s, len)
+ char *s;
+ int len;
+{
+ register char *result = (char *) xmalloc (len + 1);
+
+ bcopy (s, result, len);
+ result[len] = 0;
+ return result;
+}
+
+pfatal_with_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("%s: ", sys_errlist[errno], "");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+perror_with_name (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("%s: ", sys_errlist[errno], "");
+ else
+ s = "cannot open %s";
+ error (s, name);
+}
+
+perror_exec (name)
+ char *name;
+{
+ extern int errno, sys_nerr;
+ extern char *sys_errlist[];
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("installation problem, cannot exec %s: ",
+ sys_errlist[errno], "");
+ else
+ s = "installation problem, cannot exec %s";
+ error (s, name);
+}
+
+/* More 'friendly' abort that prints the line and file.
+ config.h can #define abort fancy_abort if you like that sort of thing. */
+
+void
+fancy_abort ()
+{
+ fatal ("Internal gcc abort.");
+}
+\f
+#ifdef HAVE_VPRINTF
+
+/* Output an error message and exit */
+
+int
+fatal (va_alist)
+ va_dcl
+{
+ va_list ap;
+ char *format;
+
+ va_start(ap);
+ format = va_arg (ap, char *);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+ delete_temp_files (0);
+ exit (1);
+}
+
+error (va_alist)
+ va_dcl
+{
+ va_list ap;
+ char *format;
+
+ va_start(ap);
+ format = va_arg (ap, char *);
+ fprintf (stderr, "%s: ", programname);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+
+ fprintf (stderr, "\n");
+}
+
+#else /* not HAVE_VPRINTF */
+
+fatal (msg, arg1, arg2)
+ char *msg, *arg1, *arg2;
+{
+ error (msg, arg1, arg2);
+ delete_temp_files (0);
+ exit (1);
+}
+
+error (msg, arg1, arg2)
+ char *msg, *arg1, *arg2;
+{
+ fprintf (stderr, "%s: ", programname);
+ fprintf (stderr, msg, arg1, arg2);
+ fprintf (stderr, "\n");
+}
+
+#endif /* not HAVE_VPRINTF */
+
+\f
+void
+validate_all_switches ()
+{
+ struct compiler *comp;
+ register char *p;
+ register char c;
+
+ for (comp = compilers; comp->spec; comp++)
+ {
+ p = comp->spec;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+ }
+
+ p = link_spec;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+
+ /* Now notice switches mentioned in the machine-specific specs. */
+
+#ifdef ASM_SPEC
+ p = ASM_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef CPP_SPEC
+ p = CPP_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef SIGNED_CHAR_SPEC
+ p = SIGNED_CHAR_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef CC1_SPEC
+ p = CC1_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef LINK_SPEC
+ p = LINK_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef LIB_SPEC
+ p = LIB_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+
+#ifdef STARTFILE_SPEC
+ p = STARTFILE_SPEC;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+#endif
+}
+
+/* Look at the switch-name that comes after START
+ and mark as valid all supplied switches that match it. */
+
+void
+validate_switches (start)
+ char *start;
+{
+ register char *p = start;
+ char *filter;
+ register int i;
+
+ if (*p == '|')
+ ++p;
+
+ if (*p == '!')
+ ++p;
+
+ filter = p;
+ while (*p != ':' && *p != '}') p++;
+
+ if (p[-1] == '*')
+ {
+ /* Mark all matching switches as valid. */
+ --p;
+ for (i = 0; i < n_switches; i++)
+ if (!strncmp (switches[i].part1, filter, p - filter))
+ switches[i].valid = 1;
+ }
+ else
+ {
+ /* Mark an exact matching switch as valid. */
+ for (i = 0; i < n_switches; i++)
+ {
+ if (!strncmp (switches[i].part1, filter, p - filter)
+ && switches[i].part1[p - filter] == 0)
+ switches[i].valid = 1;
+ }
+ }
+}