OSDN Git Service

* rtl.h (addr_diff_vec_flags): New typedef.
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 876c896..5f53c24 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,5 +1,5 @@
 /* Compiler driver program that can handle many languages.
-   Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -31,37 +31,27 @@ 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".  */
 \f
-#include <sys/types.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#ifndef NO_SYS_FILE_H
-#include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
-#endif
-
 #include "config.h"
-#include "obstack.h"
+
 #include "gansidecl.h"
+#include "system.h"
 
+#include <signal.h>
+#include <sys/stat.h>
 #ifdef __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
-#include <stdio.h>
 
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
+#include "obstack.h"
+
 
 /* ??? Need to find a GCC header to put these in.  */
 extern int pexecute PROTO ((const char *, char * const *, const char *,
                            const char *, char **, char **, int));
 extern int pwait PROTO ((int, int *, int));
+extern char *update_path PROTO((char *, char *));
 /* Flag arguments to pexecute.  */
 #define PEXECUTE_FIRST   1
 #define PEXECUTE_LAST    2
@@ -132,26 +122,19 @@ static char dir_separator_str[] = {DIR_SEPARATOR, 0};
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-extern void free ();
-extern char *getenv ();
-
 extern char *choose_temp_base PROTO((void));
 
-#ifndef errno
-extern int errno;
-#endif
-
 #ifndef HAVE_STRERROR
 extern int sys_nerr;
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
 extern char *sys_errlist[];
-#endif
 #else
 extern char *strerror();
 #endif
 
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
+
 /* If a stage of compilation returns an exit status >= 1,
    compilation of that file ceases.  */
 
@@ -206,9 +189,9 @@ static char *spec_machine = DEFAULT_TARGET_MACHINE;
    When -b is used, the value comes from the `specs' file.  */
 
 #ifdef CROSS_COMPILE
-static int cross_compile = 1;
+static char *cross_compile = "1";
 #else
-static int cross_compile = 0;
+static char *cross_compile = "0";
 #endif
 
 /* The number of errors that have occurred; the link phase will not be
@@ -231,12 +214,15 @@ extern char *version_string;
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 
+static void init_spec          PROTO((void));
+static void read_specs         PROTO((char *, int));
 static void set_spec           PROTO((char *, char *));
 static struct compiler *lookup_compiler PROTO((char *, int, char *));
 static char *build_search_list PROTO((struct path_prefix *, char *, int));
 static void putenv_from_prefixes PROTO((struct path_prefix *, char *));
 static char *find_a_file       PROTO((struct path_prefix *, char *, int));
-static void add_prefix         PROTO((struct path_prefix *, char *, int, int, int *));
+static void add_prefix         PROTO((struct path_prefix *, char *, char *,
+                                      int, int, int *));
 static char *skip_whitespace   PROTO((char *));
 static void record_temp_file   PROTO((char *, int, int));
 static void delete_if_ordinary PROTO((char *));
@@ -253,7 +239,7 @@ static char *find_file              PROTO((char *));
 static int is_directory                PROTO((char *, char *, int));
 static void validate_switches  PROTO((char *));
 static void validate_all_switches PROTO((void));
-static void give_switch                PROTO((int, int));
+static void give_switch                PROTO((int, int, int));
 static int used_arg            PROTO((char *, int));
 static int default_arg         PROTO((char *, int));
 static void set_multilib_dir   PROTO((void));
@@ -362,6 +348,7 @@ or with constant text in a single argument.
        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*} likewise, but don't put a blank between a switch and any args.
  %{S*:X} substitutes X if one or more switches whose names start with -S are
        specified to CC.  Note that the tail part of the -S option
        (i.e. the part matched by the `*') will be substituted for each
@@ -513,10 +500,6 @@ static char *multilib_defaults;
 
 static char *multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 
-#ifdef EXTRA_SPECS
-static struct { char *name, *spec; } extra_specs[] = { EXTRA_SPECS };
-#endif
-
 struct user_specs {
   struct user_specs *next;
   char *filename;
@@ -526,11 +509,12 @@ static struct user_specs *user_specs_head, *user_specs_tail;
 
 /* This defines which switch letters take arguments.  */
 
-#define DEFAULT_SWITCH_TAKES_ARG(CHAR)      \
+#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
   ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
    || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
    || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
-   || (CHAR) == 'L' || (CHAR) == 'A')
+   || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \
+   || (CHAR) == 'B' || (CHAR) == 'b')
 
 #ifndef SWITCH_TAKES_ARG
 #define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
@@ -581,13 +565,14 @@ static int n_compilers;
 static struct compiler default_compilers[] =
 {
   /* Add lists of suffixes of known languages here.  If those languages
-     were no present when we built the driver, we will hit these copies
-     and given a more meaningful error than "file not used since
+     were not present when we built the driver, we will hit these copies
+     and be given a more meaningful error than "file not used since
      linking is not done".  */
   {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"}, {".c++", "#C++"},
   {".C", "#C++"}, {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
   {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
   {".fpp", "#Fortran"},
+  {".p", "#Pascal"}, {".pas", "#Pascal"},
   /* Next come the entries for C.  */
   {".c", "@c"},
   {"@c",
@@ -597,7 +582,8 @@ static struct compiler default_compilers[] =
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
        %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs} \
-        %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+        %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+        %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
         %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
@@ -618,7 +604,8 @@ static struct compiler default_compilers[] =
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
        %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
-        %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+        %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+        %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
         %i %W{o*}}\
@@ -631,7 +618,8 @@ static struct compiler default_compilers[] =
         -undef -D__OBJC__ -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
         %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
-        %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+        %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+        %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
         %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
@@ -655,7 +643,8 @@ static struct compiler default_compilers[] =
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
         %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
-        %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+        %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+        %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
         %i %W{o*}"},
@@ -681,7 +670,8 @@ static struct compiler default_compilers[] =
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG} %{trigraphs}\
         -undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
-        %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+        %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+        %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
         %i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
@@ -1028,126 +1018,6 @@ my_strerror(e)
 #endif
 }
 \f
-/* Read compilation specs from a file named FILENAME,
-   replacing the default ones.
-
-   A suffix which starts with `*' is a definition for
-   one of the machine-specific sub-specs.  The "suffix" should be
-   *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
-   The corresponding spec is stored in asm_spec, etc.,
-   rather than in the `compilers' vector.
-
-   Anything invalid in the file is a fatal error.  */
-
-static void
-read_specs (filename)
-     char *filename;
-{
-  int desc;
-  int readlen;
-  struct stat statbuf;
-  char *buffer;
-  register char *p;
-
-  if (verbose_flag)
-    fprintf (stderr, "Reading specs from %s\n", filename);
-
-  /* Open and stat the file.  */
-  desc = open (filename, O_RDONLY, 0);
-  if (desc < 0)
-    pfatal_with_name (filename);
-  if (stat (filename, &statbuf) < 0)
-    pfatal_with_name (filename);
-
-  /* Read contents of file into BUFFER.  */
-  buffer = xmalloc ((unsigned) statbuf.st_size + 1);
-  readlen = read (desc, buffer, (unsigned) statbuf.st_size);
-  if (readlen < 0)
-    pfatal_with_name (filename);
-  buffer[readlen] = 0;
-  close (desc);
-
-  /* Scan BUFFER for specs, putting them in the vector.  */
-  p = buffer;
-  while (1)
-    {
-      char *suffix;
-      char *spec;
-      char *in, *out, *p1, *p2;
-
-      /* Advance P in BUFFER to the next nonblank nocomment line.  */
-      p = skip_whitespace (p);
-      if (*p == 0)
-       break;
-
-      /* Find the colon that should end the suffix.  */
-      p1 = p;
-      while (*p1 && *p1 != ':' && *p1 != '\n') p1++;
-      /* The colon shouldn't be missing.  */
-      if (*p1 != ':')
-       fatal ("specs file malformed after %d characters", p1 - buffer);
-      /* Skip back over trailing whitespace.  */
-      p2 = p1;
-      while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t')) p2--;
-      /* Copy the suffix to a string.  */
-      suffix = save_string (p, p2 - p);
-      /* Find the next line.  */
-      p = skip_whitespace (p1 + 1);
-      if (p[1] == 0)
-       fatal ("specs file malformed after %d characters", p - buffer);
-      p1 = p;
-      /* Find next blank line.  */
-      while (*p1 && !(*p1 == '\n' && p1[1] == '\n')) p1++;
-      /* Specs end at the blank line and do not include the newline.  */
-      spec = save_string (p, p1 - p);
-      p = p1;
-
-      /* Delete backslash-newline sequences from the spec.  */
-      in = spec;
-      out = spec;
-      while (*in != 0)
-       {
-         if (in[0] == '\\' && in[1] == '\n')
-           in += 2;
-         else if (in[0] == '#')
-           {
-             while (*in && *in != '\n') in++;
-           }
-         else
-           *out++ = *in++;
-       }
-      *out = 0;
-
-      if (suffix[0] == '*')
-       {
-         if (! strcmp (suffix, "*link_command"))
-           link_command_spec = spec;
-         else
-           set_spec (suffix + 1, spec);
-       }
-      else
-       {
-         /* Add this pair to the vector.  */
-         compilers
-           = ((struct compiler *)
-              xrealloc (compilers, (n_compilers + 2) * sizeof (struct compiler)));
-         compilers[n_compilers].suffix = suffix;
-         bzero ((char *) compilers[n_compilers].spec,
-                sizeof compilers[n_compilers].spec);
-         compilers[n_compilers].spec[0] = spec;
-         n_compilers++;
-         bzero ((char *) &compilers[n_compilers],
-                sizeof compilers[n_compilers]);
-       }
-
-      if (*suffix == 0)
-       link_command_spec = spec;
-    }
-
-  if (link_command_spec == 0)
-    fatal ("spec file has no spec for linking");
-}
-
 static char *
 skip_whitespace (p)
      char *p;
@@ -1178,14 +1048,90 @@ skip_whitespace (p)
 
 struct spec_list
 {
-  char *name;                 /* Name of the spec.  */
-  char *spec;                 /* The spec itself.  */
-  struct spec_list *next;     /* Next spec in linked list.  */
+                               /* The following 2 fields must be first */
+                               /* to allow EXTRA_SPECS to be initialized */
+  char *name;                  /* name of the spec.  */
+  char *ptr;                   /* available ptr if no static pointer */
+
+                               /* The following fields are not initialized */
+                               /* by EXTRA_SPECS */
+  char **ptr_spec;             /* pointer to the spec itself.  */
+  struct spec_list *next;      /* Next spec in linked list.  */
+  int name_len;                        /* length of the name */
+  int alloc_p;                 /* whether string was allocated */
 };
 
-/* List of specs that have been defined so far.  */
+#define INIT_STATIC_SPEC(NAME,PTR) \
+{ NAME, NULL_PTR, PTR, (struct spec_list *)0, sizeof (NAME)-1, 0 }
+
+/* List of statically defined specs */
+static struct spec_list static_specs[] = {
+  INIT_STATIC_SPEC ("asm",                     &asm_spec),
+  INIT_STATIC_SPEC ("asm_final",               &asm_final_spec),
+  INIT_STATIC_SPEC ("cpp",                     &cpp_spec),
+  INIT_STATIC_SPEC ("cc1",                     &cc1_spec),
+  INIT_STATIC_SPEC ("cc1plus",                 &cc1plus_spec),
+  INIT_STATIC_SPEC ("endfile",                 &endfile_spec),
+  INIT_STATIC_SPEC ("link",                    &link_spec),
+  INIT_STATIC_SPEC ("lib",                     &lib_spec),
+  INIT_STATIC_SPEC ("libgcc",                  &libgcc_spec),
+  INIT_STATIC_SPEC ("startfile",               &startfile_spec),
+  INIT_STATIC_SPEC ("switches_need_spaces",    &switches_need_spaces),
+  INIT_STATIC_SPEC ("signed_char",             &signed_char_spec),
+  INIT_STATIC_SPEC ("predefines",              &cpp_predefines),
+  INIT_STATIC_SPEC ("cross_compile",           &cross_compile),
+  INIT_STATIC_SPEC ("version",                 &compiler_version),
+  INIT_STATIC_SPEC ("multilib",                        &multilib_select),
+  INIT_STATIC_SPEC ("multilib_defaults",       &multilib_defaults),
+  INIT_STATIC_SPEC ("multilib_extra",          &multilib_extra),
+  INIT_STATIC_SPEC ("multilib_matches",                &multilib_matches),
+};
+
+#ifdef EXTRA_SPECS             /* additional specs needed */
+static struct spec_list extra_specs[] = { EXTRA_SPECS };
+#endif
+
+/* List of dynamically allocates specs that have been defined so far.  */
+
+static struct spec_list *specs = (struct spec_list *)0;
+
+\f
+/* Initialize the specs lookup routines.  */
+
+static void
+init_spec ()
+{
+  struct spec_list *next = (struct spec_list *)0;
+  struct spec_list *sl   = (struct spec_list *)0;
+  int i;
+
+  if (specs)
+    return;                    /* already initialized */
+
+  if (verbose_flag)
+    fprintf (stderr, "Using builtin specs.\n");
+
+#ifdef EXTRA_SPECS
+  for (i = (sizeof (extra_specs) / sizeof (extra_specs[0])) - 1; i >= 0; i--)
+    {
+      sl = &extra_specs[i];
+      sl->next = next;
+      sl->name_len = strlen (sl->name);
+      sl->ptr_spec = &sl->ptr;
+      next = sl;
+    }
+#endif
+
+  for (i = (sizeof (static_specs) / sizeof (static_specs[0])) - 1; i >= 0; i--)
+    {
+      sl = &static_specs[i];
+      sl->next = next;
+      next = sl;
+    }
+
+  specs = sl;
+}
 
-static struct spec_list *specs = (struct spec_list *) 0;
 \f
 /* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
    removed; If the spec starts with a + then SPEC is added to the end of the
@@ -1198,10 +1144,26 @@ set_spec (name, spec)
 {
   struct spec_list *sl;
   char *old_spec;
+  int name_len = strlen (name);
+  int i;
+
+  /* If this is the first call, initialize the statically allocated specs */
+  if (!specs)
+    {
+      struct spec_list *next = (struct spec_list *)0;
+      for (i = (sizeof (static_specs) / sizeof (static_specs[0])) - 1;
+          i >= 0; i--)
+       {
+         sl = &static_specs[i];
+         sl->next = next;
+         next = sl;
+       }
+      specs = sl;
+    }
 
   /* See if the spec already exists */
   for (sl = specs; sl; sl = sl->next)
-    if (strcmp (sl->name, name) == 0)
+    if (name_len == sl->name_len && !strcmp (sl->name, name))
       break;
 
   if (!sl)
@@ -1209,73 +1171,29 @@ set_spec (name, spec)
       /* Not found - make it */
       sl = (struct spec_list *) xmalloc (sizeof (struct spec_list));
       sl->name = save_string (name, strlen (name));
-      sl->spec = save_string ("", 0);
+      sl->name_len = name_len;
+      sl->ptr_spec = &sl->ptr;
+      sl->alloc_p = 0;
+      *(sl->ptr_spec) = "";
       sl->next = specs;
       specs = sl;
     }
 
-  old_spec = sl->spec;
-  if (name && spec[0] == '+' && isspace (spec[1]))
-    sl->spec = concat (old_spec, spec + 1, NULL_PTR);
-  else
-    sl->spec = save_string (spec, strlen (spec));
-
-  if (! strcmp (name, "asm"))
-    asm_spec = sl->spec;
-  else if (! strcmp (name, "asm_final"))
-    asm_final_spec = sl->spec;
-  else if (! strcmp (name, "cc1"))
-    cc1_spec = sl->spec;
-  else if (! strcmp (name, "cc1plus"))
-    cc1plus_spec = sl->spec;
-  else if (! strcmp (name, "cpp"))
-    cpp_spec = sl->spec;
-  else if (! strcmp (name, "endfile"))
-    endfile_spec = sl->spec;
-  else if (! strcmp (name, "lib"))
-    lib_spec = sl->spec;
-  else if (! strcmp (name, "libgcc"))
-    libgcc_spec = sl->spec;
-  else if (! strcmp (name, "link"))
-    link_spec = sl->spec;
-  else if (! strcmp (name, "predefines"))
-    cpp_predefines = sl->spec;
-  else if (! strcmp (name, "signed_char"))
-    signed_char_spec = sl->spec;
-  else if (! strcmp (name, "startfile"))
-    startfile_spec = sl->spec;
-  else if (! strcmp (name, "switches_need_spaces"))
-    switches_need_spaces = sl->spec;
-  else if (! strcmp (name, "cross_compile"))
-    cross_compile = atoi (sl->spec);
-  else if (! strcmp (name, "multilib"))
-    multilib_select = sl->spec;
-  else if (! strcmp (name, "multilib_matches"))
-    multilib_matches = sl->spec;
-  else if (! strcmp (name, "multilib_extra"))
-    multilib_extra = sl->spec;
-  else if (! strcmp (name, "multilib_defaults"))
-    multilib_defaults = sl->spec;
-  else if (! strcmp (name, "version"))
-    compiler_version = sl->spec;
-#ifdef EXTRA_SPECS
-  else
-    {
-      int i;
-      for (i = 0; i < sizeof (extra_specs) / sizeof (extra_specs[0]); i++)
-       {
-         if (! strcmp (name, extra_specs[i].name))
-           {
-             extra_specs[i].spec = sl->spec;
-             break;
-           }
-       }
-    }
+  old_spec = *(sl->ptr_spec);
+  *(sl->ptr_spec) = ((spec[0] == '+' && ISSPACE (spec[1]))
+                    ? concat (old_spec, spec + 1, NULL_PTR)
+                    : save_string (spec, strlen (spec)));
+
+#ifdef DEBUG_SPECS
+  if (verbose_flag)
+    fprintf (stderr, "Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
 #endif
 
   /* Free the old spec */
-  if (old_spec)
+  if (old_spec && sl->alloc_p)
     free (old_spec);
+
+  sl->alloc_p = 1;
 }
 \f
 /* Accumulate a command (program name and args), and run it.  */
@@ -1424,9 +1342,8 @@ store_arg (arg, delete_always, delete_failure)
      int delete_always, delete_failure;
 {
   if (argbuf_index + 1 == argbuf_length)
-    {
-      argbuf = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
-    }
+    argbuf
+      = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
 
   argbuf[argbuf_index++] = arg;
   argbuf[argbuf_index] = 0;
@@ -1435,6 +1352,262 @@ store_arg (arg, delete_always, delete_failure)
     record_temp_file (arg, delete_always, delete_failure);
 }
 \f
+/* Read compilation specs from a file named FILENAME,
+   replacing the default ones.
+
+   A suffix which starts with `*' is a definition for
+   one of the machine-specific sub-specs.  The "suffix" should be
+   *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
+   The corresponding spec is stored in asm_spec, etc.,
+   rather than in the `compilers' vector.
+
+   Anything invalid in the file is a fatal error.  */
+
+static void
+read_specs (filename, main_p)
+     char *filename;
+     int main_p;
+{
+  int desc;
+  int readlen;
+  struct stat statbuf;
+  char *buffer;
+  register char *p;
+
+  if (verbose_flag)
+    fprintf (stderr, "Reading specs from %s\n", filename);
+
+  /* Open and stat the file.  */
+  desc = open (filename, O_RDONLY, 0);
+  if (desc < 0)
+    pfatal_with_name (filename);
+  if (stat (filename, &statbuf) < 0)
+    pfatal_with_name (filename);
+
+  /* Read contents of file into BUFFER.  */
+  buffer = xmalloc ((unsigned) statbuf.st_size + 1);
+  readlen = read (desc, buffer, (unsigned) statbuf.st_size);
+  if (readlen < 0)
+    pfatal_with_name (filename);
+  buffer[readlen] = 0;
+  close (desc);
+
+  /* Scan BUFFER for specs, putting them in the vector.  */
+  p = buffer;
+  while (1)
+    {
+      char *suffix;
+      char *spec;
+      char *in, *out, *p1, *p2, *p3;
+
+      /* Advance P in BUFFER to the next nonblank nocomment line.  */
+      p = skip_whitespace (p);
+      if (*p == 0)
+       break;
+
+      /* Is this a special command that starts with '%'? */
+      /* Don't allow this for the main specs file, since it would
+        encourage people to overwrite it.  */
+      if (*p == '%' && !main_p)
+       {
+         p1 = p;
+         while (*p && *p != '\n')
+           p++;
+
+         p++;                  /* Skip '\n' */
+
+         if (!strncmp (p1, "%include", sizeof ("%include")-1)
+             && (p1[sizeof "%include" - 1] == ' '
+                 || p1[sizeof "%include" - 1] == '\t'))
+           {
+             char *new_filename;
+
+             p1 += sizeof ("%include");
+             while (*p1 == ' ' || *p1 == '\t')
+               p1++;
+
+             if (*p1++ != '<' || p[-2] != '>')
+               fatal ("specs %%include syntax malformed after %d characters",
+                      p1 - buffer + 1);
+
+             p[-2] = '\0';
+             new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
+             read_specs (new_filename ? new_filename : p1, FALSE);
+             continue;
+           }
+         else if (!strncmp (p1, "%include_noerr", sizeof "%include_noerr" - 1)
+                  && (p1[sizeof "%include_noerr" - 1] == ' '
+                      || p1[sizeof "%include_noerr" - 1] == '\t'))
+           {
+             char *new_filename;
+
+             p1 += sizeof "%include_noerr";
+             while (*p1 == ' ' || *p1 == '\t') p1++;
+
+             if (*p1++ != '<' || p[-2] != '>')
+               fatal ("specs %%include syntax malformed after %d characters",
+                      p1 - buffer + 1);
+
+             p[-2] = '\0';
+             new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
+             if (new_filename)
+               read_specs (new_filename, FALSE);
+             else if (verbose_flag)
+               fprintf (stderr, "Could not find specs file %s\n", p1);
+             continue;
+           }
+         else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
+                  && (p1[sizeof "%rename" - 1] == ' '
+                      || p1[sizeof "%rename" - 1] == '\t'))
+           {
+             int name_len;
+             struct spec_list *sl;
+
+             /* Get original name */
+             p1 += sizeof "%rename";
+             while (*p1 == ' ' || *p1 == '\t')
+               p1++;
+
+             if (! ISALPHA (*p1))
+               fatal ("specs %%rename syntax malformed after %d characters",
+                      p1 - buffer);
+
+             p2 = p1;
+             while (*p2 && !ISSPACE (*p2))
+               p2++;
+
+             if (*p2 != ' ' && *p2 != '\t')
+               fatal ("specs %%rename syntax malformed after %d characters",
+                      p2 - buffer);
+
+             name_len = p2 - p1;
+             *p2++ = '\0';
+             while (*p2 == ' ' || *p2 == '\t')
+               p2++;
+
+             if (! ISALPHA (*p2))
+               fatal ("specs %%rename syntax malformed after %d characters",
+                      p2 - buffer);
+
+             /* Get new spec name */
+             p3 = p2;
+             while (*p3 && !ISSPACE (*p3))
+               p3++;
+
+             if (p3 != p-1)
+               fatal ("specs %%rename syntax malformed after %d characters",
+                      p3 - buffer);
+             *p3 = '\0';
+
+             for (sl = specs; sl; sl = sl->next)
+               if (name_len == sl->name_len && !strcmp (sl->name, p1))
+                 break;
+
+             if (!sl)
+               fatal ("specs %s spec was not found to be renamed", p1);
+
+             if (strcmp (p1, p2) == 0)
+               continue;
+
+             if (verbose_flag)
+               {
+                 fprintf (stderr, "rename spec %s to %s\n", p1, p2);
+#ifdef DEBUG_SPECS
+                 fprintf (stderr, "spec is '%s'\n\n", *(sl->ptr_spec));
+#endif
+               }
+
+             set_spec (p2, *(sl->ptr_spec));
+             if (sl->alloc_p)
+               free (*(sl->ptr_spec));
+
+             *(sl->ptr_spec) = "";
+             sl->alloc_p = 0;
+             continue;
+           }
+         else
+           fatal ("specs unknown %% command after %d characters",
+                  p1 - buffer);
+       }
+
+      /* Find the colon that should end the suffix.  */
+      p1 = p;
+      while (*p1 && *p1 != ':' && *p1 != '\n')
+       p1++;
+
+      /* The colon shouldn't be missing.  */
+      if (*p1 != ':')
+       fatal ("specs file malformed after %d characters", p1 - buffer);
+
+      /* Skip back over trailing whitespace.  */
+      p2 = p1;
+      while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t'))
+       p2--;
+
+      /* Copy the suffix to a string.  */
+      suffix = save_string (p, p2 - p);
+      /* Find the next line.  */
+      p = skip_whitespace (p1 + 1);
+      if (p[1] == 0)
+       fatal ("specs file malformed after %d characters", p - buffer);
+
+      p1 = p;
+      /* Find next blank line.  */
+      while (*p1 && !(*p1 == '\n' && p1[1] == '\n'))
+       p1++;
+
+      /* Specs end at the blank line and do not include the newline.  */
+      spec = save_string (p, p1 - p);
+      p = p1;
+
+      /* Delete backslash-newline sequences from the spec.  */
+      in = spec;
+      out = spec;
+      while (*in != 0)
+       {
+         if (in[0] == '\\' && in[1] == '\n')
+           in += 2;
+         else if (in[0] == '#')
+           while (*in && *in != '\n')
+             in++;
+
+         else
+           *out++ = *in++;
+       }
+      *out = 0;
+
+      if (suffix[0] == '*')
+       {
+         if (! strcmp (suffix, "*link_command"))
+           link_command_spec = spec;
+         else
+           set_spec (suffix + 1, spec);
+       }
+      else
+       {
+         /* Add this pair to the vector.  */
+         compilers
+           = ((struct compiler *)
+              xrealloc (compilers,
+                        (n_compilers + 2) * sizeof (struct compiler)));
+
+         compilers[n_compilers].suffix = suffix;
+         bzero ((char *) compilers[n_compilers].spec,
+                sizeof compilers[n_compilers].spec);
+         compilers[n_compilers].spec[0] = spec;
+         n_compilers++;
+         bzero ((char *) &compilers[n_compilers],
+                sizeof compilers[n_compilers]);
+       }
+
+      if (*suffix == 0)
+       link_command_spec = spec;
+    }
+
+  if (link_command_spec == 0)
+    fatal ("spec file has no spec for linking");
+}
+\f
 /* Record the names of temporary files we tell compilers to write,
    and delete them at the end of the run.  */
 
@@ -1490,10 +1663,12 @@ record_temp_file (filename, always_delete, fail_delete)
       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:;
     }
 
@@ -1503,10 +1678,12 @@ record_temp_file (filename, always_delete, fail_delete)
       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:;
     }
 }
@@ -1525,7 +1702,9 @@ delete_if_ordinary (name)
   fflush (stdout);
   i = getchar ();
   if (i != '\n')
-    while ((c = getchar ()) != '\n' && c != EOF) ;
+    while ((c = getchar ()) != '\n' && c != EOF)
+      ;
+
   if (i == 'y' || i == 'Y')
 #endif /* DEBUG */
     if (stat (name, &st) >= 0 && S_ISREG (st.st_mode))
@@ -1641,7 +1820,7 @@ build_search_list (paths, prefix, check_dir_p)
       int len = strlen (pprefix->prefix);
 
       if (machine_suffix
-         && (!check_dir_p
+         && (! check_dir_p
              || is_directory (pprefix->prefix, machine_suffix, 0)))
        {
          if (!first_time)
@@ -1654,10 +1833,10 @@ build_search_list (paths, prefix, check_dir_p)
 
       if (just_machine_suffix
          && pprefix->require_machine_suffix == 2
-         && (!check_dir_p
+         && (! check_dir_p
              || is_directory (pprefix->prefix, just_machine_suffix, 0)))
        {
-         if (!first_time)
+         if (! first_time)
            obstack_1grow (&collect_obstack, PATH_SEPARATOR);
            
          first_time = FALSE;
@@ -1666,15 +1845,16 @@ build_search_list (paths, prefix, check_dir_p)
                        just_suffix_len);
        }
 
-      if (!pprefix->require_machine_suffix)
+      if (! pprefix->require_machine_suffix)
        {
-         if (!first_time)
+         if (! first_time)
            obstack_1grow (&collect_obstack, PATH_SEPARATOR);
 
          first_time = FALSE;
          obstack_grow (&collect_obstack, pprefix->prefix, len);
        }
     }
+
   obstack_1grow (&collect_obstack, '\0');
   return obstack_finish (&collect_obstack);
 }
@@ -1712,7 +1892,10 @@ find_a_file (pprefix, name, mode)
 
   /* Determine the filename to execute (special case for absolute paths).  */
 
-  if (*name == '/' || *name == DIR_SEPARATOR)
+  if (*name == '/' || *name == DIR_SEPARATOR
+      /* Check for disk name on MS-DOS-based systems.  */
+      || (DIR_SEPARATOR == '\\' && name[1] == ':'
+         && (name[2] == DIR_SEPARATOR || name[2] == '/')))
     {
       if (access (name, mode))
        {
@@ -1786,7 +1969,7 @@ find_a_file (pprefix, name, mode)
 
        /* Certain prefixes can't be used without the machine suffix
           when the machine or version is explicitly specified.  */
-       if (!pl->require_machine_suffix)
+       if (! pl->require_machine_suffix)
          {
            /* Some systems have a suffix for executable files.
               So try appending that first.  */
@@ -1825,14 +2008,17 @@ find_a_file (pprefix, name, mode)
    through this prefix.  WARN should point to an int
    which will be set to 1 if this entry is used.
 
+   COMPONENT is the value to be passed to update_path.
+
    REQUIRE_MACHINE_SUFFIX is 1 if this prefix can't be used without
    the complete value of machine_suffix.
    2 means try both machine_suffix and just_machine_suffix.  */
 
 static void
-add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
+add_prefix (pprefix, prefix, component, first, require_machine_suffix, warn)
      struct path_prefix *pprefix;
      char *prefix;
+     char *component;
      int first;
      int require_machine_suffix;
      int *warn;
@@ -1840,7 +2026,7 @@ add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
   struct prefix_list *pl, **prev;
   int len;
 
-  if (!first && pprefix->plist)
+  if (! first && pprefix->plist)
     {
       for (pl = pprefix->plist; pl->next; pl = pl->next)
        ;
@@ -1851,6 +2037,7 @@ add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
 
   /* Keep track of the longest prefix */
 
+  prefix = update_path (prefix, component);
   len = strlen (prefix);
   if (len > pprefix->max_len)
     pprefix->max_len = len;
@@ -1890,28 +2077,11 @@ unused_prefix_warnings (pprefix)
          /* Prevent duplicate warnings.  */
          *pl->used_flag_ptr = 1;
        }
-      pl = pl->next;
-    }
-}
-
-/* Get rid of all prefixes built up so far in *PLISTP.  */
-
-static void
-free_path_prefix (pprefix)
-     struct path_prefix *pprefix;
-{
-  struct prefix_list *pl = pprefix->plist;
-  struct prefix_list *temp;
 
-  while (pl)
-    {
-      temp = pl;
       pl = pl->next;
-      free (temp->prefix);
-      free ((char *) temp);
     }
-  pprefix->plist = (struct prefix_list *) 0;
 }
+
 \f
 /* Execute the command specified by the arguments on the current line of spec.
    When using pipes, this includes several piped-together commands
@@ -1956,7 +2126,7 @@ execute ()
   for (n_commands = 1, i = 0; i < argbuf_index; i++)
     if (strcmp (argbuf[i], "|") == 0)
       {                                /* each command.  */
-#if defined (__MSDOS__) || (defined (_WIN32) && ! defined (__CYGWIN32__)) || defined (OS2)
+#if defined (__MSDOS__) || (defined (_WIN32) && defined (__CYGWIN32_)) || defined (OS2) || defined (VMS)
         fatal ("-pipe not supported");
 #endif
        argbuf[i] = 0;  /* termination of command args.  */
@@ -1993,7 +2163,9 @@ execute ()
       fflush (stderr);
       i = getchar ();
       if (i != '\n')
-       while (getchar () != '\n') ;
+       while (getchar () != '\n')
+         ;
+
       if (i != 'y' && i != 'Y')
        return 0;
 #endif /* DEBUG */
@@ -2135,7 +2307,7 @@ convert_filename (name, do_exe)
       && name[len - 2] == '.'
       && name[len - 1] == 'o')
     {
-      obstack_grow (&obstack, name[i], len - 2);
+      obstack_grow (&obstack, name, len - 2);
       obstack_grow0 (&obstack, OBJECT_SUFFIX, strlen (OBJECT_SUFFIX));
       name = obstack_finish (&obstack);
     }
@@ -2201,8 +2373,8 @@ process_command (argc, argv)
 
   if (gcc_exec_prefix)
     {
-      add_prefix (&exec_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
-      add_prefix (&startfile_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
+      add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
+      add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
     }
 
   /* COMPILER_PATH and LIBRARY_PATH have values
@@ -2229,7 +2401,10 @@ process_command (argc, argv)
                }
              else
                nstore[endp-startp] = 0;
-             add_prefix (&exec_prefixes, nstore, 0, 0, NULL_PTR);
+             add_prefix (&exec_prefixes, nstore, 0, 0, 0, NULL_PTR);
+             add_prefix (&include_prefixes,
+                         concat (nstore, "include", NULL_PTR),
+                         0, 0, 0, NULL_PTR);
              if (*endp == 0)
                break;
              endp = startp = endp + 1;
@@ -2240,7 +2415,7 @@ process_command (argc, argv)
     }
 
   temp = getenv ("LIBRARY_PATH");
-  if (temp && ! cross_compile)
+  if (temp && *cross_compile == '0')
     {
       char *startp, *endp;
       char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2260,7 +2435,8 @@ process_command (argc, argv)
                }
              else
                nstore[endp-startp] = 0;
-             add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
+             add_prefix (&startfile_prefixes, nstore, NULL_PTR,
+                         0, 0, NULL_PTR);
              if (*endp == 0)
                break;
              endp = startp = endp + 1;
@@ -2272,7 +2448,7 @@ process_command (argc, argv)
 
   /* Use LPATH like LIBRARY_PATH (for the CMU build program).  */
   temp = getenv ("LPATH");
-  if (temp && ! cross_compile)
+  if (temp && *cross_compile == '0')
     {
       char *startp, *endp;
       char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2292,7 +2468,8 @@ process_command (argc, argv)
                }
              else
                nstore[endp-startp] = 0;
-             add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
+             add_prefix (&startfile_prefixes, nstore, NULL_PTR,
+                         0, 0, NULL_PTR);
              if (*endp == 0)
                break;
              endp = startp = endp + 1;
@@ -2307,7 +2484,7 @@ process_command (argc, argv)
 
 #ifdef LANG_SPECIFIC_DRIVER
   /* Do language-specific adjustment/addition of flags.  */
-  lang_specific_driver (&fatal, &argc, &argv);
+  lang_specific_driver (fatal, &argc, &argv);
 #endif
 
   /* Scan argv twice.  Here, the first time, just count how many switches
@@ -2318,34 +2495,10 @@ process_command (argc, argv)
     {
       if (! strcmp (argv[i], "-dumpspecs"))
        {
-         printf ("*asm:\n%s\n\n", asm_spec);
-         printf ("*asm_final:\n%s\n\n", asm_final_spec);
-         printf ("*cpp:\n%s\n\n", cpp_spec);
-         printf ("*cc1:\n%s\n\n", cc1_spec);
-         printf ("*cc1plus:\n%s\n\n", cc1plus_spec);
-         printf ("*endfile:\n%s\n\n", endfile_spec);
-         printf ("*link:\n%s\n\n", link_spec);
-         printf ("*lib:\n%s\n\n", lib_spec);
-         printf ("*libgcc:\n%s\n\n", libgcc_spec);
-         printf ("*startfile:\n%s\n\n", startfile_spec);
-         printf ("*switches_need_spaces:\n%s\n\n", switches_need_spaces);
-         printf ("*signed_char:\n%s\n\n", signed_char_spec);
-         printf ("*predefines:\n%s\n\n", cpp_predefines);
-         printf ("*cross_compile:\n%d\n\n", cross_compile);
-         printf ("*version:\n%s\n\n", compiler_version);
-         printf ("*multilib:\n%s\n\n", multilib_select);
-         printf ("*multilib_defaults:\n%s\n\n", multilib_defaults);
-         printf ("*multilib_extra:\n%s\n\n", multilib_extra);
-         printf ("*multilib_matches:\n%s\n\n", multilib_matches);
-
-#ifdef EXTRA_SPECS
-         {
-           int j;
-           for (j = 0; j < sizeof (extra_specs) / sizeof (extra_specs[0]); j++)
-             printf ("*%s:\n%s\n\n", extra_specs[j].name,
-                     (extra_specs[j].spec) ? extra_specs[j].spec : "");
-         }
-#endif
+         struct spec_list *sl;
+         init_spec ();
+         for (sl = specs; sl; sl = sl->next)
+           printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
          exit (0);
        }
       else if (! strcmp (argv[i], "-dumpversion"))
@@ -2493,6 +2646,7 @@ process_command (argc, argv)
          switch (c)
            {
            case 'b':
+              n_switches++;
              if (p[1] == 0 && i + 1 == argc)
                fatal ("argument to `-b' is missing");
              if (p[1] == 0)
@@ -2505,7 +2659,6 @@ process_command (argc, argv)
 
            case 'B':
              {
-               int *temp = (int *) xmalloc (sizeof (int));
                char *value;
                if (p[1] == 0 && i + 1 == argc)
                  fatal ("argument to `-B' is missing");
@@ -2513,10 +2666,12 @@ process_command (argc, argv)
                  value = argv[++i];
                else
                  value = p + 1;
-               add_prefix (&exec_prefixes, value, 1, 0, &warn_B);
-               add_prefix (&startfile_prefixes, value, 1, 0, &warn_B);
-               add_prefix (&include_prefixes, concat (value, "include", NULL_PTR),
-                           1, 0, NULL_PTR);
+               add_prefix (&exec_prefixes, value, NULL_PTR, 1, 0, &warn_B);
+               add_prefix (&startfile_prefixes, value, NULL_PTR,
+                           1, 0, &warn_B);
+               add_prefix (&include_prefixes, concat (value, "include",
+                                                      NULL_PTR),
+                           NULL_PTR, 1, 0, NULL_PTR);
 
                /* As a kludge, if the arg is "[foo/]stageN/", just add
                   "[foo/]include" to the include prefix.  */
@@ -2527,23 +2682,24 @@ process_command (argc, argv)
                           && (value[len - 8] == '/'
                               || value[len - 8] == DIR_SEPARATOR)))
                      && strncmp (value + len - 7, "stage", 5) == 0
-                     && isdigit (value[len - 2])
+                     && ISDIGIT (value[len - 2])
                      && (value[len - 1] == '/'
                          || value[len - 1] == DIR_SEPARATOR))
                    {
                      if (len == 7)
-                       add_prefix (&include_prefixes, "include",
+                       add_prefix (&include_prefixes, "include", NULL_PTR,
                                    1, 0, NULL_PTR);
                      else
                        {
                          char *string = xmalloc (len + 1);
                          strncpy (string, value, len-7);
-                         strcat (string, "include");
-                         add_prefix (&include_prefixes, string,
+                         strcpy (string+len-7, "include");
+                         add_prefix (&include_prefixes, string, NULL_PTR,
                                      1, 0, NULL_PTR);
                        }
                    }
                }
+                n_switches++;
              }
              break;
 
@@ -2557,6 +2713,7 @@ process_command (argc, argv)
              break;
 
            case 'V':
+             n_switches++;
              if (p[1] == 0 && i + 1 == argc)
                fatal ("argument to `-V' is missing");
              if (p[1] == 0)
@@ -2612,12 +2769,16 @@ process_command (argc, argv)
   /* Use 2 as fourth arg meaning try just the machine as a suffix,
      as well as trying the machine and the version.  */
 #ifndef OS2
-  add_prefix (&exec_prefixes, standard_exec_prefix, 0, 2, warn_std_ptr);
-  add_prefix (&exec_prefixes, standard_exec_prefix_1, 0, 2, warn_std_ptr);
+  add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
+             0, 2, warn_std_ptr);
+  add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
+             0, 2, warn_std_ptr);
 #endif
 
-  add_prefix (&startfile_prefixes, standard_exec_prefix, 0, 1, warn_std_ptr);
-  add_prefix (&startfile_prefixes, standard_exec_prefix_1, 0, 1, warn_std_ptr);
+  add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
+             0, 1, warn_std_ptr);
+  add_prefix (&startfile_prefixes, standard_exec_prefix_1, "BINUTILS",
+             0, 1, warn_std_ptr);
 
   tooldir_prefix = concat (tooldir_base_prefix, spec_machine, 
                           dir_separator_str, NULL_PTR);
@@ -2640,11 +2801,11 @@ process_command (argc, argv)
          add_prefix (&exec_prefixes,
                      concat (gcc_exec_tooldir_prefix, "bin", 
                              dir_separator_str, NULL_PTR),
-                     0, 0, NULL_PTR);
+                     NULL_PTR, 0, 0, NULL_PTR);
          add_prefix (&startfile_prefixes,
                      concat (gcc_exec_tooldir_prefix, "lib", 
                              dir_separator_str, NULL_PTR),
-                     0, 0, NULL_PTR);
+                     NULL_PTR, 0, 0, NULL_PTR);
        }
 
       tooldir_prefix = concat (standard_exec_prefix, spec_machine,
@@ -2654,10 +2815,10 @@ process_command (argc, argv)
 
   add_prefix (&exec_prefixes, 
               concat (tooldir_prefix, "bin", dir_separator_str, NULL_PTR),
-             0, 0, NULL_PTR);
+             "BINUTILS", 0, 0, NULL_PTR);
   add_prefix (&startfile_prefixes,
              concat (tooldir_prefix, "lib", dir_separator_str, NULL_PTR),
-             0, 0, NULL_PTR);
+             "BINUTILS", 0, 0, NULL_PTR);
 
   /* More prefixes are enabled in main, after we read the specs file
      and determine whether this is cross-compilation or not.  */
@@ -2739,18 +2900,14 @@ process_command (argc, argv)
        i++;
       else if (strncmp (argv[i], "-specs=", 7) == 0)
        ;
+      /* -save-temps overrides -pipe, so that temp files are produced */
+      else if (save_temps_flag && strcmp (argv[i], "-pipe") == 0)
+       error ("Warning: -pipe ignored since -save-temps specified");
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
          register char *p = &argv[i][1];
          register int c = *p;
 
-         if (c == 'B' || c == 'b' || c == 'V')
-           {
-             /* Skip a separate arg, if any.  */
-             if (p[1] == 0)
-               i++;
-             continue;
-           }
          if (c == 'x')
            {
              if (p[1] == 0 && i + 1 == argc)
@@ -2812,6 +2969,12 @@ process_command (argc, argv)
          /* This is always valid, since gcc.c itself understands it.  */
          if (!strcmp (p, "save-temps"))
            switches[n_switches].valid = 1;
+          else
+            {
+              char ch = switches[n_switches].part1[0];
+              if (ch == 'V' || ch == 'b' || ch == 'B')
+                switches[n_switches].valid = 1;
+            }
          n_switches++;
        }
       else
@@ -2934,7 +3097,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
   char *string;
   int value;
 
-  while (c = *p++)
+  while ((c = *p++))
     /* If substituting a switch, treat all chars like letters.
        Otherwise, NL, SPC, TAB and % are special.  */
     switch (inswitch ? 'a' : c)
@@ -3183,7 +3346,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                   In 2.4, do something about that.  */
                struct temp_name *t;
                char *suffix = p;
-               while (*p == '.' || isalpha (*p)
+               while (*p == '.' || ISALPHA (*p)
                       || (p[0] == '%' && p[1] == 'O'))
                  p++;
 
@@ -3472,7 +3635,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                      *x++ = *y++;
 
                      if (*y != '_'
-                         || (*(y+1) != '_' && ! isupper (*(y+1))))
+                         || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
                        {
                          /* Stick __ at front of macro name.  */
                          *x++ = '_';
@@ -3514,7 +3677,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                      y += 2;
 
                      if (*y != '_'
-                         || (*(y+1) != '_' && ! isupper (*(y+1))))
+                         || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
                        {
                          /* Stick -D__ at front of macro name.  */
                          *x++ = '-';
@@ -3612,9 +3775,13 @@ do_spec_1 (spec, inswitch, soft_matched_part)
 
              /* See if it's in the list */
              for (len = p - name, sl = specs; sl; sl = sl->next)
-               if (strncmp (sl->name, name, len) == 0 && !sl->name[len])
+               if (sl->name_len == len && !strncmp (sl->name, name, len))
                  {
-                   name = sl->spec;
+                   name = *(sl->ptr_spec);
+#ifdef DEBUG_SPECS
+                   fprintf (stderr, "Processing spec %c%s%c, which is '%s'\n",
+                            c, sl->name, (c == '(') ? ')' : ']', name);
+#endif
                    break;
                  }
 
@@ -3684,7 +3851,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                 ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */
 
              /* Ignore leading non-digits.  i.e. "foo-" in "foo-2.7.2".  */
-             while (! isdigit (*v))
+             while (! ISDIGIT (*v))
                v++;
              if (v > compiler_version && v[-1] != '-')
                abort ();
@@ -3693,7 +3860,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              if (c1 == '2')
                {
                  /* Set V after the first period.  */
-                 while (isdigit (*v))
+                 while (ISDIGIT (*v))
                    v++;
                  if (*v != '.')
                    abort ();
@@ -3702,7 +3869,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
 
              /* Set Q at the next period or at the end.  */
              q = v;
-             while (isdigit (*q))
+             while (ISDIGIT (*q))
                q++;
              if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
                abort ();
@@ -3748,6 +3915,11 @@ handle_braces (p)
   int pipe_p = 0;
   int negate = 0;
   int suffix = 0;
+  int include_blanks = 1;
+
+  if (*p == '^')
+    /* A '^' after the open-brace means to not give blanks before args.  */
+    include_blanks = 0, ++p;
 
   if (*p == '|')
     /* A `|' after the open-brace means,
@@ -3813,7 +3985,7 @@ handle_braces (p)
       for (i = 0; i < n_switches; i++)
        if (!strncmp (switches[i].part1, filter, p - filter)
            && check_live_switch (i, p - filter))
-         give_switch (i, 0);
+         give_switch (i, 0, include_blanks);
     }
   else
     {
@@ -3852,7 +4024,7 @@ handle_braces (p)
                  {
                    do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
                    /* Pass any arguments this switch has.  */
-                   give_switch (i, 1);
+                   give_switch (i, 1, 1);
                  }
 
              return q;
@@ -3896,7 +4068,7 @@ handle_braces (p)
        {
          if (*p == '}')
            {
-             give_switch (i, 0);
+             give_switch (i, 0, include_blanks);
            }
          else
            {
@@ -3997,28 +4169,35 @@ check_live_switch (switchnum, prefix_length)
    the vector of switches gcc received, which is `switches'.
    This cannot fail since it never finishes a command line.
 
-   If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.  */
+   If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.
+
+   If INCLUDE_BLANKS is nonzero, then we include blanks before each argument
+   of the switch.  */
 
 static void
-give_switch (switchnum, omit_first_word)
+give_switch (switchnum, omit_first_word, include_blanks)
      int switchnum;
      int omit_first_word;
+     int include_blanks;
 {
   if (!omit_first_word)
     {
       do_spec_1 ("-", 0, NULL_PTR);
       do_spec_1 (switches[switchnum].part1, 1, NULL_PTR);
     }
-  do_spec_1 (" ", 0, NULL_PTR);
+
   if (switches[switchnum].args != 0)
     {
       char **p;
       for (p = switches[switchnum].args; *p; p++)
        {
+         if (include_blanks)
+           do_spec_1 (" ", 0, NULL_PTR);
          do_spec_1 (*p, 1, NULL_PTR);
-         do_spec_1 (" ", 0, NULL_PTR);
        }
     }
+
+  do_spec_1 (" ", 0, NULL_PTR);
   switches[switchnum].valid = 1;
 }
 \f
@@ -4212,6 +4391,53 @@ main (argc, argv)
 
   process_command (argc, argv);
 
+  {
+    int i;
+    int first_time;
+
+    /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
+       the compiler.  */
+    obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
+                 sizeof ("COLLECT_GCC_OPTIONS=")-1);
+
+    first_time = TRUE;
+    for (i = 0; i < n_switches; i++)
+      {
+       char **args;
+       char *p, *q;
+       if (!first_time)
+         obstack_grow (&collect_obstack, " ", 1);
+
+       first_time = FALSE;
+       obstack_grow (&collect_obstack, "'-", 2);
+        q = switches[i].part1;
+       while ((p = (char *) index (q,'\'')))
+          {
+            obstack_grow (&collect_obstack, q, p-q);
+            obstack_grow (&collect_obstack, "'\\''", 4);
+            q = ++p;
+          }
+        obstack_grow (&collect_obstack, q, strlen (q));
+       obstack_grow (&collect_obstack, "'", 1);
+
+       for (args = switches[i].args; args && *args; args++)
+         {
+           obstack_grow (&collect_obstack, " '", 2);
+           q = *args;
+           while ((p = (char *) index (q,'\'')))
+             {
+               obstack_grow (&collect_obstack, q, p-q);
+               obstack_grow (&collect_obstack, "'\\''", 4);
+               q = ++p;
+             }
+           obstack_grow (&collect_obstack, q, strlen (q));
+           obstack_grow (&collect_obstack, "'", 1);
+         }
+      }
+    obstack_grow (&collect_obstack, "\0", 1);
+    putenv (obstack_finish (&collect_obstack));
+  }
+
   /* Initialize the vector of specs to just the default.
      This means one element containing 0s, as a terminator.  */
 
@@ -4229,42 +4455,49 @@ main (argc, argv)
   specs_file = find_a_file (&startfile_prefixes, "specs", R_OK);
   /* Read the specs file unless it is a default one.  */
   if (specs_file != 0 && strcmp (specs_file, "specs"))
-    read_specs (specs_file);
-
-#ifdef EXTRA_SPECS
+    read_specs (specs_file, TRUE);
   else
-    {
-      int k;
-      for (k = 0; k < sizeof (extra_specs) / sizeof (extra_specs[0]); k++)
-       set_spec (extra_specs[k].name, extra_specs[k].spec);
-    }
-#endif
-
+    init_spec ();
+
+  /* We need to check standard_exec_prefix/just_machine_suffix/specs
+     for any override of as, ld and libraries. */
+  specs_file = (char *) alloca (strlen (standard_exec_prefix)
+                               + strlen (just_machine_suffix)
+                               + sizeof ("specs"));
+
+  strcpy (specs_file, standard_exec_prefix);
+  strcat (specs_file, just_machine_suffix);
+  strcat (specs_file, "specs");
+  if (access (specs_file, R_OK) == 0)
+    read_specs (specs_file, TRUE);
   /* Process any user specified specs in the order given on the command
      line.  */
   for (uptr = user_specs_head; uptr; uptr = uptr->next)
     {
       char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK);
-      read_specs (filename ? filename : uptr->filename);
+      read_specs (filename ? filename : uptr->filename, FALSE);
     }
 
   /* If not cross-compiling, look for startfiles in the standard places.  */
   /* The fact that these are done here, after reading the specs file,
      means that it cannot be found in these directories.
      But that's okay.  It should never be there anyway.  */
-  if (!cross_compile)
+  if (*cross_compile == '0')
     {
 #ifdef MD_EXEC_PREFIX
-      add_prefix (&exec_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
-      add_prefix (&startfile_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
+      add_prefix (&exec_prefixes, md_exec_prefix, "GCC", 0, 0, NULL_PTR);
+      add_prefix (&startfile_prefixes, md_exec_prefix, "GCC", 0, 0, NULL_PTR);
 #endif
 
 #ifdef MD_STARTFILE_PREFIX
-      add_prefix (&startfile_prefixes, md_startfile_prefix, 0, 0, NULL_PTR);
+      add_prefix (&startfile_prefixes, md_startfile_prefix, "GCC",
+                 0, 0, NULL_PTR);
 #endif
 
 #ifdef MD_STARTFILE_PREFIX_1
-      add_prefix (&startfile_prefixes, md_startfile_prefix_1, 0, 0, NULL_PTR);
+      add_prefix (&startfile_prefixes, md_startfile_prefix_1, "GCC",
+                 0, 0, NULL_PTR);
 #endif
 
       /* If standard_startfile_prefix is relative, base it on
@@ -4273,28 +4506,28 @@ main (argc, argv)
         standard_startfile_prefix on that as well.  */
       if (*standard_startfile_prefix == '/'
          || *standard_startfile_prefix == DIR_SEPARATOR)
-       add_prefix (&startfile_prefixes, standard_startfile_prefix, 0, 0,
-                   NULL_PTR);
+       add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
+                   0, 0, NULL_PTR);
       else
        {
          if (gcc_exec_prefix)
            add_prefix (&startfile_prefixes,
                        concat (gcc_exec_prefix, machine_suffix,
                                standard_startfile_prefix, NULL_PTR),
-                       0, 0, NULL_PTR);
+                       NULL_PTR, 0, 0, NULL_PTR);
          add_prefix (&startfile_prefixes,
                      concat (standard_exec_prefix,
                              machine_suffix,
                              standard_startfile_prefix, NULL_PTR),
-                     0, 0, NULL_PTR);
+                     NULL_PTR, 0, 0, NULL_PTR);
        }                      
 
-      add_prefix (&startfile_prefixes, standard_startfile_prefix_1, 0, 0,
-                 NULL_PTR);
-      add_prefix (&startfile_prefixes, standard_startfile_prefix_2, 0, 0,
-                 NULL_PTR);
+      add_prefix (&startfile_prefixes, standard_startfile_prefix_1,
+                 "BINUTILS", 0, 0, NULL_PTR);
+      add_prefix (&startfile_prefixes, standard_startfile_prefix_2,
+                 "BINUTILS", 0, 0, NULL_PTR);
 #if 0 /* Can cause surprises, and one can use -B./ instead.  */
-      add_prefix (&startfile_prefixes, "./", 0, 1, NULL_PTR);
+      add_prefix (&startfile_prefixes, "./", NULL_PTR, 0, 1, NULL_PTR);
 #endif
     }
   else
@@ -4303,7 +4536,7 @@ main (argc, argv)
        add_prefix (&startfile_prefixes,
                    concat (gcc_exec_prefix, machine_suffix,
                            standard_startfile_prefix, NULL_PTR),
-                   0, 0, NULL_PTR);
+                   "BINUTILS", 0, 0, NULL_PTR);
     }
 
   /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake.  */
@@ -4375,7 +4608,17 @@ main (argc, argv)
 
   if (verbose_flag)
     {
-      if (! strcmp (version_string, compiler_version))
+      int n;
+
+      /* compiler_version is truncated at the first space when initialized
+        from version string, so truncate version_string at the first space
+        before comparing.  */
+      for (n = 0; version_string[n]; n++)
+       if (version_string[n] == ' ')
+         break;
+
+      if (! strncmp (version_string, compiler_version, n)
+         && compiler_version[n] == 0)
        fprintf (stderr, "gcc version %s\n", version_string);
       else
        fprintf (stderr, "gcc driver version %s executing gcc version %s\n",
@@ -4492,40 +4735,12 @@ main (argc, argv)
   if (error_count == 0)
     {
       int tmp = execution_count;
-      int i;
-      int first_time;
 
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
         for collect.  */
       putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
       putenv_from_prefixes (&startfile_prefixes, "LIBRARY_PATH=");
 
-      /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
-        the compiler.  */
-      obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
-                   sizeof ("COLLECT_GCC_OPTIONS=")-1);
-
-      first_time = TRUE;
-      for (i = 0; i < n_switches; i++)
-       {
-         char **args;
-         if (!first_time)
-           obstack_grow (&collect_obstack, " ", 1);
-
-         first_time = FALSE;
-         obstack_grow (&collect_obstack, "-", 1);
-         obstack_grow (&collect_obstack, switches[i].part1,
-                       strlen (switches[i].part1));
-
-         for (args = switches[i].args; args && *args; args++)
-           {
-             obstack_grow (&collect_obstack, " ", 1);
-             obstack_grow (&collect_obstack, *args, strlen (*args));
-           }
-       }
-      obstack_grow (&collect_obstack, "\0", 1);
-      putenv (obstack_finish (&collect_obstack));
-
       value = do_spec (link_command_spec);
       if (value < 0)
        error_count = 1;
@@ -4834,105 +5049,28 @@ validate_all_switches ()
       for (i = 0; i < sizeof comp->spec / sizeof comp->spec[0] && comp->spec[i]; i++)
        {
          p = comp->spec[i];
-         while (c = *p++)
+         while ((c = *p++))
            if (c == '%' && *p == '{')
              /* We have a switch spec.  */
              validate_switches (p + 1);
        }
     }
 
-  /* look through the linked list of extra specs read from the specs file */
+  /* look through the linked list of specs read from the specs file */
   for (spec = specs; spec ; spec = spec->next)
     {
-      p = spec->spec;
-      while (c = *p++)
+      p = *(spec->ptr_spec);
+      while ((c = *p++))
        if (c == '%' && *p == '{')
          /* We have a switch spec.  */
          validate_switches (p + 1);
     }
 
   p = link_command_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.  */
-
-  p = asm_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = asm_final_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = cpp_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = signed_char_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = cc1_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = cc1plus_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);
-
-  p = lib_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-  p = libgcc_spec;
-  while (c = *p++)
+  while ((c = *p++))
     if (c == '%' && *p == '{')
       /* We have a switch spec.  */
       validate_switches (p + 1);
-
-  p = startfile_spec;
-  while (c = *p++)
-    if (c == '%' && *p == '{')
-      /* We have a switch spec.  */
-      validate_switches (p + 1);
-
-#ifdef EXTRA_SPECS
-  {
-    int i;
-    for (i = 0; i < sizeof (extra_specs) / sizeof (extra_specs[0]); i++)
-      {
-       p = extra_specs[i].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
@@ -4982,7 +5120,7 @@ validate_switches (start)
 }
 \f
 /* Check whether a particular argument was used.  The first time we
-   canonialize the switches to keep only the ones we care about.  */
+   canonicalize the switches to keep only the ones we care about.  */
 
 static int
 used_arg (p, len)
@@ -5078,7 +5216,6 @@ default_arg (p, len)
      int len;
 {
   char *start, *end;
-  int i;
 
   for (start = multilib_defaults; *start != '\0'; start = end+1)
     {