+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 or end of string. */
+ while (*p1 && !(*p1 == '\n' && (p1[1] == '\n' || p1[1] == '\0')))
+ 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. */
+
+/* This is the common prefix we use to make temp file names.
+ It is chosen once for each run of this program.
+ It is substituted into a spec by %g.
+ Thus, all temp file names contain this prefix.
+ In practice, all temp file names start with this prefix.
+
+ This prefix comes from the envvar TMPDIR if it is defined;
+ otherwise, from the P_tmpdir macro if that is defined;
+ otherwise, in /usr/tmp or /tmp;
+ or finally the current directory if all else fails. */
+
+static char *temp_filename;
+
+/* Length of the prefix. */
+
+static int temp_filename_length;
+
+/* Define the list of temporary files to delete. */