OSDN Git Service

Remove patch in 1.12.
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 7cb8dc1..33b220a 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-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -81,6 +81,10 @@ extern int pwait PROTO ((int, int *, int));
 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
 #endif
 
+#ifdef VMS
+#define exit __posix_exit
+#endif
+
 /* Define O_RDONLY if the system hasn't defined it for us.  */
 #ifndef O_RDONLY
 #define O_RDONLY 0
@@ -202,9 +206,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
@@ -227,6 +231,8 @@ 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));
@@ -249,7 +255,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));
@@ -358,6 +364,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
@@ -509,9 +516,12 @@ 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;
+};
+
+static struct user_specs *user_specs_head, *user_specs_tail;
 
 /* This defines which switch letters take arguments.  */
 
@@ -533,7 +543,7 @@ static struct { char *name, *spec; } extra_specs[] = { EXTRA_SPECS };
   || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
   || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
   || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
-  || !strcmp (STR, "isystem"))
+  || !strcmp (STR, "isystem") || !strcmp (STR, "specs"))
 
 #ifndef WORD_SWITCH_TAKES_ARG
 #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
@@ -584,7 +594,7 @@ 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}\
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
-       %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+       %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs} \
         %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
@@ -605,7 +615,7 @@ 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}\
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
-       %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+       %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
         %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
@@ -618,7 +628,7 @@ 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}\
         -undef -D__OBJC__ -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
-        %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+        %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
         %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
@@ -642,7 +652,7 @@ 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}\
         -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
-        %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+        %{ansi:-trigraphs -D__STRICT_ANSI__}\
        %{!undef:%{!ansi:%p} %P} %{trigraphs}\
         %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
@@ -702,9 +712,11 @@ static char *link_command_spec = "\
  %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
                        %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
                        %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
-                       %{static:} %{L*} %{T*} %o\
+                       %{static:} %{L*} %o\
                        %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
-                       %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
+                       %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
+                       %{T*}\
+                       \n }}}}}}";
 #else
 /* Use -L.  */
 static char *link_command_spec = "\
@@ -712,9 +724,11 @@ static char *link_command_spec = "\
  %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
                        %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
                        %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
-                       %{static:} %{L*} %D %{T*} %o\
+                       %{static:} %{L*} %D %o\
                        %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
-                       %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
+                       %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
+                       %{T*}\
+                       \n }}}}}}";
 #endif
 
 /* A vector of options to give to the linker.
@@ -764,7 +778,7 @@ struct option_map option_map[] =
    {"--comments", "-C", 0},
    {"--compile", "-c", 0},
    {"--debug", "-g", "oj"},
-   {"--define-macro", "-D", "a"},
+   {"--define-macro", "-D", "aj"},
    {"--dependencies", "-M", 0},
    {"--dump", "-d", "a"},
    {"--dumpbase", "-dumpbase", "a"},
@@ -776,7 +790,7 @@ struct option_map option_map[] =
    {"--imacros", "-imacros", "a"},
    {"--include", "-include", "a"},
    {"--include-barrier", "-I-", 0},
-   {"--include-directory", "-I", "a"},
+   {"--include-directory", "-I", "aj"},
    {"--include-directory-after", "-idirafter", "a"},
    {"--include-prefix", "-iprefix", "a"},
    {"--include-with-prefix", "-iwithprefix", "a"},
@@ -811,6 +825,7 @@ struct option_map option_map[] =
    {"--save-temps", "-save-temps", 0},
    {"--shared", "-shared", 0},
    {"--silent", "-q", 0},
+   {"--specs", "-specs=", "aj"},
    {"--static", "-static", 0},
    {"--symbolic", "-symbolic", 0},
    {"--target", "-b", "a"},
@@ -818,7 +833,7 @@ struct option_map option_map[] =
    {"--traditional", "-traditional", 0},
    {"--traditional-cpp", "-traditional-cpp", 0},
    {"--trigraphs", "-trigraphs", 0},
-   {"--undefine-macro", "-U", "a"},
+   {"--undefine-macro", "-U", "aj"},
    {"--use-version", "-V", "a"},
    {"--user-dependencies", "-MM", 0},
    {"--verbose", "-v", 0},
@@ -1012,126 +1027,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;
@@ -1162,14 +1057,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 */
+};
+
+#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),
 };
 
-/* List of specs that have been defined so far.  */
+#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
@@ -1182,10 +1153,25 @@ 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)
@@ -1193,73 +1179,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.  */
@@ -1419,6 +1361,241 @@ 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))
+               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.  */
 
@@ -2131,7 +2308,11 @@ convert_filename (name, do_exe)
   if (! do_exe || EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
     return name;
 
-  for (i = 0; i < len; i++)
+  for (i = len - 1; i >= 0; i--)
+    if (name[i] == '/' || name[i] == DIR_SEPARATOR)
+      break;
+
+  for (i++; i < len; i++)
     if (name[i] == '.')
       return name;
 
@@ -2220,7 +2401,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);
@@ -2252,7 +2433,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);
@@ -2285,6 +2466,11 @@ process_command (argc, argv)
   /* Convert new-style -- options to old-style.  */
   translate_options (&argc, &argv);
 
+#ifdef LANG_SPECIFIC_DRIVER
+  /* Do language-specific adjustment/addition of flags.  */
+  lang_specific_driver (&fatal, &argc, &argv);
+#endif
+
   /* 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).  */
@@ -2293,34 +2479,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"))
@@ -2430,6 +2592,36 @@ process_command (argc, argv)
          save_temps_flag = 1;
          n_switches++;
        }
+      else if (strcmp (argv[i], "-specs") == 0)
+       {
+         struct user_specs *user = (struct user_specs *)
+           xmalloc (sizeof (struct user_specs));
+         if (++i >= argc)
+           fatal ("argument to `-specs' is missing");
+
+         user->next = (struct user_specs *)0;
+         user->filename = argv[i];
+         if (user_specs_tail)
+           user_specs_tail->next = user;
+         else
+           user_specs_head = user;
+         user_specs_tail = user;
+       }
+      else if (strncmp (argv[i], "-specs=", 7) == 0)
+       {
+         struct user_specs *user = (struct user_specs *)
+           xmalloc (sizeof (struct user_specs));
+         if (strlen (argv[i]) == 7)
+           fatal ("argument to `-specs=' is missing");
+
+         user->next = (struct user_specs *)0;
+         user->filename = argv[i]+7;
+         if (user_specs_tail)
+           user_specs_tail->next = user;
+         else
+           user_specs_head = user;
+         user_specs_tail = user;
+       }
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
          register char *p = &argv[i][1];
@@ -2483,7 +2675,7 @@ process_command (argc, argv)
                        {
                          char *string = xmalloc (len + 1);
                          strncpy (string, value, len-7);
-                         strcat (string, "include");
+                         strcpy (string+len-7, "include");
                          add_prefix (&include_prefixes, string,
                                      1, 0, NULL_PTR);
                        }
@@ -2680,6 +2872,10 @@ process_command (argc, argv)
          infiles[n_infiles].language = 0;
          infiles[n_infiles++].name = argv[i];
        }
+      else if (strcmp (argv[i], "-specs") == 0)
+       i++;
+      else if (strncmp (argv[i], "-specs=", 7) == 0)
+       ;
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
          register char *p = &argv[i][1];
@@ -3553,9 +3749,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;
                  }
 
@@ -3577,6 +3777,8 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                         every -D and at the end of each arg,  */
                      while (1)
                        {
+                         int flag;
+
                          if (! strncmp (y, "-D", 2))
                            {
                              *x++ = '-';
@@ -3584,16 +3786,18 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                              *x++ = '_';
                              *x++ = '_';
                              y += 2;
+                             flag = 1;
+                             continue;
                            }
-                         else if (*y == ' ' || *y == 0)
+                          else if (flag && (*y == ' ' || *y == '\t' || *y == '='
+                                            || *y == '}' || *y == 0))
                            {
                              *x++ = '_';
                              *x++ = '_';
-                             if (*y == 0)
-                               break;
-                             else
-                               *x++ = *y++;
+                             flag = 0;
                            }
+                          if (*y == 0)
+                           break;
                          else
                            *x++ = *y++;
                        }
@@ -3685,6 +3889,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,
@@ -3750,7 +3959,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
     {
@@ -3789,7 +3998,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;
@@ -3833,7 +4042,7 @@ handle_braces (p)
        {
          if (*p == '}')
            {
-             give_switch (i, 0);
+             give_switch (i, 0, include_blanks);
            }
          else
            {
@@ -3934,28 +4143,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
@@ -4064,6 +4280,7 @@ main (argc, argv)
   char *explicit_link_files;
   char *specs_file;
   char *p;
+  struct user_specs *uptr;
 
   p = argv[0] + strlen (argv[0]);
   while (p != argv[0] && p[-1] != '/' && p[-1] != DIR_SEPARATOR) --p;
@@ -4165,22 +4382,35 @@ 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
+    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)
     {
-      int k;
-      for (k = 0; k < sizeof (extra_specs) / sizeof (extra_specs[0]); k++)
-       set_spec (extra_specs[k].name, extra_specs[k].spec);
+      char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK);
+      read_specs (filename ? filename : uptr->filename, FALSE);
     }
-#endif
 
   /* 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);
@@ -4769,10 +4999,10 @@ validate_all_switches ()
        }
     }
 
-  /* 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;
+      p = *(spec->ptr_spec);
       while (c = *p++)
        if (c == '%' && *p == '{')
          /* We have a switch spec.  */
@@ -4784,83 +5014,6 @@ validate_all_switches ()
     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++)
-    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
@@ -4936,8 +5089,8 @@ used_arg (p, len)
 
       /* Break multilib_matches into the component strings of string and replacement
          string */
-      for (p = multilib_matches; *p != '\0'; p++)
-       if (*p == ';')
+      for (q = multilib_matches; *q != '\0'; q++)
+       if (*q == ';')
          cnt++;
 
       matches = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
@@ -4970,8 +5123,13 @@ used_arg (p, len)
            break;
        }
 
-      /* Now build a list of the replacement string for switches that we care about */
-      mswitches = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr)) * n_switches);
+      /* Now build a list of the replacement string for switches that we care
+        about.  Make sure we allocate at least one entry.  This prevents
+        xmalloc from calling fatal, and prevents us from re-executing this
+        block of code.  */
+      mswitches
+       = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr))
+                                        * (n_switches ? n_switches : 1));
       for (i = 0; i < n_switches; i++)
        {
          int xlen = strlen (switches[i].part1);