File pr20425.patch of Package gcc41

This gives the gcc driver a new path iteration function, for_each_path,
and uses it everywhere, making path iteration a little more consistent.
for_each_path uses the same path ordering as the existing find_file
function.  I've also tweaked some of the existing find_a_file calls for
consistency, and uncovered and fixed some other bugs..

Functional changes are:

o  %D library paths are printed in the same order as gcc uses elsewhere
   when searching library directories, ie. all multilib paths are first.
   http://gcc.gnu.org/ml/gcc-patches/2005-03/msg02044.html effectively
   reverted by the rewrite because I believe the same speedup is gained
   by searching the right dirs first.

o  gcc -print-search-dirs prints library multilib paths followed by
   non-multilib paths where before we just printed non-multilib paths.

o  LIBRARY_PATH_ENV similarly includes multilib directories.

o  All searches of startfile_prefixes now look in multilib dirs first
   followed by non-multilib dirs.  This changes the dirs we search for
   spec files, and %include and %include_noerr in specs.  Previously
   we only searched the non-multilib dirs for specs files.  I think this
   change is worthwhile just for consistency, and the extension is
   reasonable.  For instance, it would allow different spec files to be
   used for gcc -m64 vs. gcc -m32.  However, if others think this wrong,
   I won't argue.  Consistency isn't everything.

o  Some attempt made to prevent searching of duplicate paths.  The old
   find_file would search some paths twice (when multilib_dir was NULL
   but multilib_os_dir non-NULL).  We still search twice in some cases,
   eg. /usr/lib/../lib and /usr/lib are considered different paths.

o  find_a_file with last param (do_multi) true now searches both
   multilib and non-multilib paths.  Before, do_multi (well, the old
   param name was multilib) meant just search multilib paths.  This
   isn't a user-visible change as the only place where find_a_file was
   invoked with the last param true was from find_file, where we
   immediately followed with a non-multilib find_a_file.

o  Memory leaks fixed in is_directory.

o  LIBRARY_PATH_ENV and COMPILER_PATH now only have existing
   directories, making LIBRARY_PATH_ENV closer to %D paths.  The
   following lines (which I remove) in is_directory meant that
   is_directory didn't do much for LIBRARY_PATH_ENV, except on
   SMALL_ARG_MAX machines.

  4278        ian #ifndef SMALL_ARG_MAX
  4278        ian   if (! linker)
  4278        ian     return 1;
  4278        ian #endif

   I'll also remove mention of SMALL_ARG_MAX in config and doc files
   when I commit this change as this is the only place it is used.

o  gcc -Bnon-dir-prefix- now works properly.  The previously mentioned
   is_directory peculiarity affected the following code.

 43664      nickc /* Catch the case where the user has forgotten to append a
 46063      jsm28    directory separator to the path.  Note, they may be using
 43664      nickc    -B to add an executable name prefix, eg "i386-elf-", in
 43664      nickc    order to distinguish between multiple installations of
 43664      nickc    GCC in the same directory.  Hence we must check to see
 43664      nickc    if appending a directory separator actually makes a
 43664      nickc    valid directory name.  */
 43664      nickc if (! IS_DIR_SEPARATOR (value [len - 1])
 43664      nickc     && is_directory (value, "", 0))
 43664      nickc   {
 43767      ghazi     char *tmp = xmalloc (len + 2);
 43767      ghazi     strcpy (tmp, value);
 43767      ghazi     tmp[len] = DIR_SEPARATOR;
 43767      ghazi     tmp[++ len] = 0;
 43767      ghazi     value = tmp;
 43664      nickc   }

Bootstrapped and regression tested powerpc64-linux and powerpc-linux on
a previous iteration of this patch missing is_directory fixes.
Currently running tests on this patch.

	* gcc.c (for_each_path): New function.
	(add_to_obstack, file_at_path): New functions.
	(struct file_at_path_info, struct add_to_obstack_info): New.
	(build_search_list): Rewrite using for_each_path.  Constify struct
	path_prefix pointer.  Add do_multi param.  Adjust all callers.
	(find_a_file): Similarly, but just change existing param to bool.
	(putenv_from_prefixes): Add do_multi param, make "paths" const.
	(do_spec_path): Delete.
	(struct spec_path_info): New.
	(spec_path): New function.
	(do_spec_1): Use for_each_path for %D and %I.
	(find_file): Adjust for find_a_file changes.
	(main): Search multilibs for specs.  Print multilib lib path for
	-print-search-dirs.  Likewise add multilibs to LIBRARY_PATH_ENV.
	(read_specs): Search multilibs for %include and %include_noerr.
	(is_directory): Remove second string param.  Change last param
	to a bool.  Don't use concat.  Remove SMALL_ARG_MAX test, always
	check path is a dir.  Update all callers.

Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c.orig	2006-11-07 18:33:22.000000000 +0100
+++ gcc/gcc.c	2009-11-20 13:40:59.000000000 +0100
@@ -287,10 +287,12 @@ static char *load_specs (const char *);
 static void read_specs (const char *, int);
 static void set_spec (const char *, const char *);
 static struct compiler *lookup_compiler (const char *, size_t, const char *);
-static char *build_search_list (struct path_prefix *, const char *, int);
-static void putenv_from_prefixes (struct path_prefix *, const char *);
+static char *build_search_list (const struct path_prefix *, const char *,
+				bool, bool);
+static void putenv_from_prefixes (const struct path_prefix *, const char *,
+				  bool);
 static int access_check (const char *, int);
-static char *find_a_file (struct path_prefix *, const char *, int, int);
+static char *find_a_file (const struct path_prefix *, const char *, int, bool);
 static void add_prefix (struct path_prefix *, const char *, const char *,
 			int, int, int);
 static void add_sysrooted_prefix (struct path_prefix *, const char *,
@@ -313,13 +315,12 @@ static const char *eval_spec_function (c
 static const char *handle_spec_function (const char *);
 static char *save_string (const char *, int);
 static void set_collect_gcc_options (void);
-static void do_spec_path (struct prefix_list *, const char *, int, int, int, const char *, const char *);
 static int do_spec_1 (const char *, int, const char *);
 static int do_spec_2 (const char *);
 static void do_option_spec (const char *, const char *);
 static void do_self_spec (const char *);
 static const char *find_file (const char *);
-static int is_directory (const char *, const char *, int);
+static int is_directory (const char *, bool);
 static const char *validate_switches (const char *);
 static void validate_all_switches (void);
 static inline void validate_switches_from_spec (const char *);
@@ -2036,7 +2037,7 @@ read_specs (const char *filename, int ma
 		       (long) (p1 - buffer + 1));
 
 	      p[-2] = '\0';
-	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0);
+	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
 	      read_specs (new_filename ? new_filename : p1, FALSE);
 	      continue;
 	    }
@@ -2055,7 +2056,7 @@ read_specs (const char *filename, int ma
 		       (long) (p1 - buffer + 1));
 
 	      p[-2] = '\0';
-	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0);
+	      new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
 	      if (new_filename)
 		read_specs (new_filename, FALSE);
 	      else if (verbose_flag)
@@ -2352,65 +2353,214 @@ clear_failure_queue (void)
   failure_delete_queue = 0;
 }
 
-/* Build a list of search directories from PATHS.
-   PREFIX is a string to prepend to the list.
-   If CHECK_DIR_P is nonzero we ensure the directory exists.
-   This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
-   It is also used by the --print-search-dirs flag.  */
-
-static char *
-build_search_list (struct path_prefix *paths, const char *prefix,
-		   int check_dir_p)
+/* Call CALLBACK for each path in PATHS, breaking out early if CALLBACK
+   returns non-NULL.
+   If DO_MULTI is true iterate over the paths twice, first with multilib
+   suffix then without, otherwise iterate over the paths once without
+   adding a multilib suffix.  When DO_MULTI is true, some attempt is made
+   to avoid visiting the same path twice, but we could do better.  For
+   instance, /usr/lib/../lib is considered different from /usr/lib.
+   At least EXTRA_SPACE chars past the end of the path passed to
+   CALLBACK are available for use by the callback.
+   CALLBACK_INFO allows extra parameters to be passed to CALLBACK.
+
+   Returns the value returned by CALLBACK.  */
+
+static void *
+for_each_path (const struct path_prefix *paths,
+	       bool do_multi,
+	       size_t extra_space,
+	       void *(*callback) (char *, void *),
+	       void *callback_info)
 {
-  int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
-  int just_suffix_len
-    = (just_machine_suffix) ? strlen (just_machine_suffix) : 0;
-  int first_time = TRUE;
-  struct prefix_list *pprefix;
-
-  obstack_grow (&collect_obstack, prefix, strlen (prefix));
-  obstack_1grow (&collect_obstack, '=');
+  struct prefix_list *pl;
+  const char *multi_dir = NULL;
+  const char *multi_os_dir = NULL;
+  const char *multi_suffix;
+  const char *just_multi_suffix;
+  char *path = NULL;
+  void *ret = NULL;
+  bool skip_multi_dir = false;
+  bool skip_multi_os_dir = false;
+
+  multi_suffix = machine_suffix;
+  just_multi_suffix = just_machine_suffix;
+  if (do_multi && multilib_dir && strcmp (multilib_dir, ".") != 0)
+    {
+      multi_dir = concat (multilib_dir, dir_separator_str, NULL);
+      multi_suffix = concat (multi_suffix, multi_dir, NULL);
+      just_multi_suffix = concat (just_multi_suffix, multi_dir, NULL);
+    }
+  if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
+    multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
 
-  for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
+  while (1)
     {
-      int len = strlen (pprefix->prefix);
+      size_t multi_dir_len = 0;
+      size_t multi_os_dir_len = 0;
+      size_t suffix_len;
+      size_t just_suffix_len;
+      size_t len;
+
+      if (multi_dir)
+	multi_dir_len = strlen (multi_dir);
+      if (multi_os_dir)
+	multi_os_dir_len = strlen (multi_os_dir);
+      suffix_len = strlen (multi_suffix);
+      just_suffix_len = strlen (just_multi_suffix);
+
+      if (path == NULL)
+	{
+	  len = paths->max_len + extra_space + 1;
+	  if (suffix_len > multi_os_dir_len)
+	    len += suffix_len;
+	  else
+	    len += multi_os_dir_len;
+	  path = xmalloc (len);
+	}
 
-      if (machine_suffix
-	  && (! check_dir_p
-	      || is_directory (pprefix->prefix, machine_suffix, 0)))
+      for (pl = paths->plist; pl != 0; pl = pl->next)
 	{
-	  if (!first_time)
-	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
+	  len = strlen (pl->prefix);
+	  memcpy (path, pl->prefix, len);
 
-	  first_time = FALSE;
-	  obstack_grow (&collect_obstack, pprefix->prefix, len);
-	  obstack_grow (&collect_obstack, machine_suffix, suffix_len);
-	}
+	  /* Look first in MACHINE/VERSION subdirectory.  */
+	  if (!skip_multi_dir)
+	    {
+	      memcpy (path + len, multi_suffix, suffix_len + 1);
+	      ret = callback (path, callback_info);
+	      if (ret)
+		break;
+	    }
 
-      if (just_machine_suffix
-	  && pprefix->require_machine_suffix == 2
-	  && (! check_dir_p
-	      || is_directory (pprefix->prefix, just_machine_suffix, 0)))
-	{
-	  if (! first_time)
-	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
+	  /* Some paths are tried with just the machine (ie. target)
+	     subdir.  This is used for finding as, ld, etc.  */
+	  if (!skip_multi_dir
+	      && pl->require_machine_suffix == 2)
+	    {
+	      memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
+	      ret = callback (path, callback_info);
+	      if (ret)
+		break;
+	    }
+
+	  /* Now try the base path.  */
+	  if (!pl->require_machine_suffix
+	      && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir))
+	    {
+	      const char *this_multi;
+	      size_t this_multi_len;
+
+	      if (pl->os_multilib)
+		{
+		  this_multi = multi_os_dir;
+		  this_multi_len = multi_os_dir_len;
+		}
+	      else
+		{
+		  this_multi = multi_dir;
+		  this_multi_len = multi_dir_len;
+		}
 
-	  first_time = FALSE;
-	  obstack_grow (&collect_obstack, pprefix->prefix, len);
-	  obstack_grow (&collect_obstack, just_machine_suffix,
-			just_suffix_len);
+	      if (this_multi_len)
+		memcpy (path + len, this_multi, this_multi_len + 1);
+	      else
+		path[len] = '\0';
+
+	      ret = callback (path, callback_info);
+	      if (ret)
+		break;
+	    }
 	}
+      if (pl)
+	break;
 
-      if (! pprefix->require_machine_suffix)
-	{
-	  if (! first_time)
-	    obstack_1grow (&collect_obstack, PATH_SEPARATOR);
+      if (multi_dir == NULL && multi_os_dir == NULL)
+	break;
 
-	  first_time = FALSE;
-	  obstack_grow (&collect_obstack, pprefix->prefix, len);
+      /* Run through the paths again, this time without multilibs.
+	 Don't repeat any we have already seen.  */
+      if (multi_dir)
+	{
+	  free ((char *) multi_dir);
+	  multi_dir = NULL;
+	  free ((char *) multi_suffix);
+	  multi_suffix = machine_suffix;
+	  free ((char *) just_multi_suffix);
+	  just_multi_suffix = just_machine_suffix;
+	}
+      else
+	skip_multi_dir = true;
+      if (multi_os_dir)
+	{
+	  free ((char *) multi_os_dir);
+	  multi_os_dir = NULL;
 	}
+      else
+	skip_multi_os_dir = true;
     }
 
+  if (multi_dir)
+    {
+      free ((char *) multi_dir);
+      free ((char *) multi_suffix);
+      free ((char *) just_multi_suffix);
+    }
+  if (multi_os_dir)
+    free ((char *) multi_os_dir);
+  if (ret != path)
+    free (path);
+  return ret;
+}
+
+/* Callback for build_search_list.  Adds path to obstack being built.  */
+
+struct add_to_obstack_info {
+  struct obstack *ob;
+  bool check_dir;
+  bool first_time;
+};
+
+static void *
+add_to_obstack (char *path, void *data)
+{
+  struct add_to_obstack_info *info = data;
+
+  if (info->check_dir && !is_directory (path, false))
+    return NULL;
+
+  if (!info->first_time)
+    obstack_1grow (info->ob, PATH_SEPARATOR);
+
+  obstack_grow (info->ob, path, strlen (path));
+
+  info->first_time = false;
+  return NULL;
+}
+
+/* Build a list of search directories from PATHS.
+   PREFIX is a string to prepend to the list.
+   If CHECK_DIR_P is true we ensure the directory exists.
+   If DO_MULTI is true, multilib paths are output first, then
+   non-multilib paths.
+   This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
+   It is also used by the --print-search-dirs flag.  */
+
+static char *
+build_search_list (const struct path_prefix *paths, const char *prefix,
+		   bool check_dir, bool do_multi)
+{
+  struct add_to_obstack_info info;
+
+  info.ob = &collect_obstack;
+  info.check_dir = check_dir;
+  info.first_time = true;
+
+  obstack_grow (&collect_obstack, prefix, strlen (prefix));
+  obstack_1grow (&collect_obstack, '=');
+
+  for_each_path (paths, do_multi, 0, add_to_obstack, &info);
+
   obstack_1grow (&collect_obstack, '\0');
   return XOBFINISH (&collect_obstack, char *);
 }
@@ -2419,9 +2569,10 @@ build_search_list (struct path_prefix *p
    for collect.  */
 
 static void
-putenv_from_prefixes (struct path_prefix *paths, const char *env_var)
+putenv_from_prefixes (const struct path_prefix *paths, const char *env_var,
+		      bool do_multi)
 {
-  putenv (build_search_list (paths, env_var, 1));
+  putenv (build_search_list (paths, env_var, true, do_multi));
 }
 
 /* Check whether NAME can be accessed in MODE.  This is like access,
@@ -2442,20 +2593,53 @@ access_check (const char *name, int mode
   return access (name, mode);
 }
 
+/* Callback for find_a_file.  Appends the file name to the directory
+   path.  If the resulting file exists in the right mode, return the
+   full pathname to the file.  */
+
+struct file_at_path_info {
+  const char *name;
+  const char *suffix;
+  int name_len;
+  int suffix_len;
+  int mode;
+};
+
+static void *
+file_at_path (char *path, void *data)
+{
+  struct file_at_path_info *info = data;
+  size_t len = strlen (path);
+
+  memcpy (path + len, info->name, info->name_len);
+  len += info->name_len;
+
+  /* Some systems have a suffix for executable files.
+     So try appending that first.  */
+  if (info->suffix_len)
+    {
+      memcpy (path + len, info->suffix, info->suffix_len + 1);
+      if (access_check (path, info->mode) == 0)
+	return path;
+    }
+
+  path[len] = '\0';
+  if (access_check (path, info->mode) == 0)
+    return path;
+
+  return NULL;
+}
+
 /* Search for NAME using the prefix list PREFIXES.  MODE is passed to
-   access to check permissions.
+   access to check permissions.  If DO_MULTI is true, search multilib
+   paths then non-multilib paths, otherwise do not search multilib paths.
    Return 0 if not found, otherwise return its name, allocated with malloc.  */
 
 static char *
-find_a_file (struct path_prefix *pprefix, const char *name, int mode,
-	     int multilib)
+find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
+	     bool do_multi)
 {
-  char *temp;
-  const char *const file_suffix =
-    ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "");
-  struct prefix_list *pl;
-  int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
-  const char *multilib_name, *multilib_os_name;
+  struct file_at_path_info info;
 
 #ifdef DEFAULT_ASSEMBLER
   if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
@@ -2467,112 +2651,24 @@ find_a_file (struct path_prefix *pprefix
     return xstrdup (DEFAULT_LINKER);
 #endif
 
-  if (machine_suffix)
-    len += strlen (machine_suffix);
-
-  multilib_name = name;
-  multilib_os_name = name;
-  if (multilib && multilib_os_dir)
-    {
-      int len1 = multilib_dir ? strlen (multilib_dir) + 1 : 0;
-      int len2 = strlen (multilib_os_dir) + 1;
-
-      len += len1 > len2 ? len1 : len2;
-      if (multilib_dir)
-	multilib_name = ACONCAT ((multilib_dir, dir_separator_str, name,
-				  NULL));
-      if (strcmp (multilib_os_dir, ".") != 0)
-	multilib_os_name = ACONCAT ((multilib_os_dir, dir_separator_str, name,
-				    NULL));
-    }
-
-  temp = xmalloc (len);
-
   /* Determine the filename to execute (special case for absolute paths).  */
 
   if (IS_ABSOLUTE_PATH (name))
     {
       if (access (name, mode) == 0)
-	{
-	  strcpy (temp, name);
-	  return temp;
-	}
-    }
-  else
-    for (pl = pprefix->plist; pl; pl = pl->next)
-      {
-	const char *this_name
-	  = pl->os_multilib ? multilib_os_name : multilib_name;
+	return xstrdup (name);
 
-	if (machine_suffix)
-	  {
-	    /* Some systems have a suffix for executable files.
-	       So try appending that first.  */
-	    if (file_suffix[0] != 0)
-	      {
-		strcpy (temp, pl->prefix);
-		strcat (temp, machine_suffix);
-		strcat (temp, multilib_name);
-		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
-		  return temp;
-	      }
-
-	    /* Now try just the multilib_name.  */
-	    strcpy (temp, pl->prefix);
-	    strcat (temp, machine_suffix);
-	    strcat (temp, multilib_name);
-	    if (access_check (temp, mode) == 0)
-	      return temp;
-	  }
-
-	/* Certain prefixes are tried with just the machine type,
-	   not the version.  This is used for finding as, ld, etc.  */
-	if (just_machine_suffix && pl->require_machine_suffix == 2)
-	  {
-	    /* Some systems have a suffix for executable files.
-	       So try appending that first.  */
-	    if (file_suffix[0] != 0)
-	      {
-		strcpy (temp, pl->prefix);
-		strcat (temp, just_machine_suffix);
-		strcat (temp, multilib_name);
-		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
-		  return temp;
-	      }
-
-	    strcpy (temp, pl->prefix);
-	    strcat (temp, just_machine_suffix);
-	    strcat (temp, multilib_name);
-	    if (access_check (temp, mode) == 0)
-	      return temp;
-	  }
-
-	/* Certain prefixes can't be used without the machine suffix
-	   when the machine or version is explicitly specified.  */
-	if (! pl->require_machine_suffix)
-	  {
-	    /* Some systems have a suffix for executable files.
-	       So try appending that first.  */
-	    if (file_suffix[0] != 0)
-	      {
-		strcpy (temp, pl->prefix);
-		strcat (temp, this_name);
-		strcat (temp, file_suffix);
-		if (access_check (temp, mode) == 0)
-		  return temp;
-	      }
+      return NULL;
+    }
 
-	    strcpy (temp, pl->prefix);
-	    strcat (temp, this_name);
-	    if (access_check (temp, mode) == 0)
-	      return temp;
-	  }
-      }
+  info.name = name;
+  info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
+  info.name_len = strlen (info.name);
+  info.suffix_len = strlen (info.suffix);
+  info.mode = mode;
 
-  free (temp);
-  return 0;
+  return for_each_path (pprefix, do_multi, info.name_len + info.suffix_len,
+			file_at_path, &info);
 }
 
 /* Ranking of prefixes in the sort list. -B prefixes are put before
@@ -2691,7 +2787,7 @@ execute (void)
 
   commands[0].prog = argbuf[0]; /* first command.  */
   commands[0].argv = &argbuf[0];
-  string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, 0);
+  string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
 
   if (string)
     commands[0].argv[0] = string;
@@ -2706,7 +2802,7 @@ execute (void)
 	commands[n_commands].prog = argbuf[i + 1];
 	commands[n_commands].argv = &argbuf[i + 1];
 	string = find_a_file (&exec_prefixes, commands[n_commands].prog,
-			      X_OK, 0);
+			      X_OK, false);
 	if (string)
 	  commands[n_commands].argv[0] = string;
 	n_commands++;
@@ -3646,7 +3742,7 @@ warranty; not even for MERCHANTABILITY o
 		   if appending a directory separator actually makes a
 		   valid directory name.  */
 		if (! IS_DIR_SEPARATOR (value [len - 1])
-		    && is_directory (value, "", 0))
+		    && is_directory (value, false))
 		  {
 		    char *tmp = xmalloc (len + 2);
 		    strcpy (tmp, value);
@@ -4394,108 +4490,55 @@ do_self_spec (const char *spec)
     }
 }
 
-void
-do_spec_path (struct prefix_list *pl, const char *option,
-	      int omit_if_relative, int separate_options,
-	      int only_subdir,
-	      const char *dir_for_machine_suffix,
-	      const char *dir_for_no_suffix)
-{
-  static size_t bufsize = 0;
-  static char *buffer;
-  int idx;
-  bool multilib_p = false;
-
-  /* Used on systems which record the specified -L dirs
-     and use them to search for dynamic linking.  */
-  /* Relative directories always come from -B,
-     and it is better not to use them for searching
-     at run time.  In particular, stage1 loses.  */
-  if (omit_if_relative
-      && !IS_ABSOLUTE_PATH (pl->prefix))
-    return;
+/* Callback for processing %D and %I specs.  */
 
-  /* Try subdirectory if there is one.  */
-  if (machine_suffix && dir_for_machine_suffix)
-    {
-      if (strlen (pl->prefix) + strlen (machine_suffix)
-	  >= bufsize)
-	bufsize = (strlen (pl->prefix)
-		  + strlen (machine_suffix)) * 2 + 1;
-      buffer = xrealloc (buffer, bufsize);
-      strcpy (buffer, pl->prefix);
-      strcat (buffer, machine_suffix);
-      if (is_directory (buffer, dir_for_machine_suffix, 1))
-	{
-	  multilib_p = true;
-	  do_spec_1 (option, separate_options, NULL);
-	  if (separate_options)
-	    do_spec_1 (" ", 0, NULL);
-	  do_spec_1 (buffer, 1, NULL);
-	  do_spec_1 (dir_for_machine_suffix, 1, NULL);
-	  /* Make this a separate argument.  */
-	  do_spec_1 (" ", 0, NULL);
-	}
-    }
-  if (!pl->require_machine_suffix && dir_for_no_suffix)
+struct spec_path_info {
+  const char *option;
+  const char *append;
+  size_t append_len;
+  bool omit_relative;
+  bool separate_options;
+};
+
+static void *
+spec_path (char *path, void *data)
+{
+  struct spec_path_info *info = data;
+  size_t len = 0;
+  char save = 0;
+
+  if (info->omit_relative && !IS_ABSOLUTE_PATH (path))
+    return NULL;
+
+  if (info->append_len != 0)
     {
-      if (is_directory (pl->prefix, dir_for_no_suffix, 1))
-	{
-	  multilib_p = true;
-	  do_spec_1 (option, separate_options, NULL);
-	  if (separate_options)
-	    do_spec_1 (" ", 0, NULL);
-	  do_spec_1 (pl->prefix, 1, NULL);
-	  do_spec_1 (dir_for_no_suffix, 1, NULL);
-	  /* Make this a separate argument.  */
-	  do_spec_1 (" ", 0, NULL);
-	}
+      len = strlen (path);
+      memcpy (path + len, info->append, info->append_len + 1);
     }
 
-  if (only_subdir || multilib_p)
-    return;
+  if (!is_directory (path, true))
+    return NULL;
+
+  do_spec_1 (info->option, 1, NULL);
+  if (info->separate_options)
+    do_spec_1 (" ", 0, NULL);
 
-  if (machine_suffix)
+  if (info->append_len == 0)
     {
-      if (is_directory (pl->prefix, machine_suffix, 1))
-	{
-	  do_spec_1 (option, separate_options, NULL);
-	  if (separate_options)
-	    do_spec_1 (" ", 0, NULL);
-	  do_spec_1 (pl->prefix, 1, NULL);
-	  /* Remove slash from machine_suffix.  */
-	  if (strlen (machine_suffix) >= bufsize)
-	    bufsize = strlen (machine_suffix) * 2 + 1;
-	  buffer = xrealloc (buffer, bufsize);
-	  strcpy (buffer, machine_suffix);
-	  idx = strlen (buffer);
-	  if (IS_DIR_SEPARATOR (buffer[idx - 1]))
-	    buffer[idx - 1] = 0;
-	  do_spec_1 (buffer, 1, NULL);
-	  /* Make this a separate argument.  */
-	  do_spec_1 (" ", 0, NULL);
-	}
-    }
-  if (!pl->require_machine_suffix)
-    {
-      if (is_directory (pl->prefix, "", 1))
-	{
-	  do_spec_1 (option, separate_options, NULL);
-	  if (separate_options)
-	    do_spec_1 (" ", 0, NULL);
-	  /* Remove slash from pl->prefix.  */
-	  if (strlen (pl->prefix) >= bufsize)
-	    bufsize = strlen (pl->prefix) * 2 + 1;
-	  buffer = xrealloc (buffer, bufsize);
-	  strcpy (buffer, pl->prefix);
-	  idx = strlen (buffer);
-	  if (IS_DIR_SEPARATOR (buffer[idx - 1]))
-	    buffer[idx - 1] = 0;
-	  do_spec_1 (buffer, 1, NULL);
-	  /* Make this a separate argument.  */
-	  do_spec_1 (" ", 0, NULL);
-	}
+      len = strlen (path);
+      save = path[len - 1];
+      if (IS_DIR_SEPARATOR (path[len - 1]))
+	path[len - 1] = '\0';
     }
+
+  do_spec_1 (path, 1, NULL);
+  do_spec_1 (" ", 0, NULL);
+
+  /* Must not damage the original path.  */
+  if (info->append_len == 0)
+    path[len - 1] = save;
+
+  return NULL;
 }
 
 /* Process the sub-spec SPEC as a portion of a larger spec.
@@ -4633,23 +4676,23 @@ do_spec_1 (const char *spec, int inswitc
 	     that we search for startfiles.  */
 	  case 'D':
 	    {
-	      struct prefix_list *pl = startfile_prefixes.plist;
-
-	      for (; pl; pl = pl->next)
-		{
-		  const char *no_suffix_multilib_dir;
+	      struct spec_path_info info;
 
-		  no_suffix_multilib_dir = pl->os_multilib ? multilib_os_dir
-					   : multilib_dir;
-		  /* Do not separate options, include non-multilibbed variant.  */
-		  do_spec_path (pl, "-L",
+	      info.option = "-L";
+	      info.append_len = 0;
 #ifdef RELATIVE_PREFIX_NOT_LINKDIR
-				1,
+	      /* Used on systems which record the specified -L dirs
+		 and use them to search for dynamic linking.
+		 Relative directories always come from -B,
+		 and it is better not to use them for searching
+		 at run time.  In particular, stage1 loses.  */
+	      info.omit_relative = true;
 #else
-				0,
+	      info.omit_relative = false;
 #endif
-				0, 0, multilib_dir, no_suffix_multilib_dir);
-		}
+	      info.separate_options = false;
+
+	      for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
 	    }
 	    break;
 
@@ -4886,7 +4929,7 @@ do_spec_1 (const char *spec, int inswitc
 
 	  case 'I':
 	    {
-	      struct prefix_list *pl = include_prefixes.plist;
+	      struct spec_path_info info;
 
 	      if (gcc_exec_prefix)
 		{
@@ -4909,9 +4952,14 @@ do_spec_1 (const char *spec, int inswitc
 		  do_spec_1 (" ", 0, NULL);
 		}
 
-	      for (; pl; pl = pl->next)
-		/* Separate options, don't include non-suffixed variant.  */
-		do_spec_path (pl, "-isystem", 0, 1, 1, "include", "include");
+	      info.option = "-isystem";
+	      info.append = "include";
+	      info.append_len = strlen (info.append);
+	      info.omit_relative = false;
+	      info.separate_options = true;
+
+	      for_each_path (&include_prefixes, false, info.append_len,
+			     spec_path, &info);
 	    }
 	    break;
 
@@ -5897,48 +5945,27 @@ give_switch (int switchnum, int omit_fir
 static const char *
 find_file (const char *name)
 {
-  char *newname;
-
-  /* Try multilib_dir if it is defined.  */
-  if (multilib_os_dir != NULL)
-    {
-      newname = find_a_file (&startfile_prefixes, name, R_OK, 1);
-
-      /* If we don't find it in the multi library dir, then fall
-	 through and look for it in the normal places.  */
-      if (newname != NULL)
-	return newname;
-    }
-
-  newname = find_a_file (&startfile_prefixes, name, R_OK, 0);
+  char *newname = find_a_file (&startfile_prefixes, name, R_OK, true);
   return newname ? newname : name;
 }
 
 /* Determine whether a directory exists.  If LINKER, return 0 for
-   certain fixed names not needed by the linker.  If not LINKER, it is
-   only important to return 0 if the host machine has a small ARG_MAX
-   limit.  */
+   certain fixed names not needed by the linker.  */
 
 static int
-is_directory (const char *path1, const char *path2, int linker)
+is_directory (const char *path1, bool linker)
 {
-  int len1 = strlen (path1);
-  int len2 = strlen (path2);
-  char *path = alloca (3 + len1 + len2);
+  int len1;
+  char *path;
   char *cp;
   struct stat st;
 
-#ifndef SMALL_ARG_MAX
-  if (! linker)
-    return 1;
-#endif
-
-  /* Construct the path from the two parts.  Ensure the string ends with "/.".
-     The resulting path will be a directory even if the given path is a
-     symbolic link.  */
+  /* Ensure the string ends with "/.".  The resulting path will be a
+     directory even if the given path is a symbolic link.  */
+  len1 = strlen (path1);
+  path = alloca (3 + len1);
   memcpy (path, path1, len1);
-  memcpy (path + len1, path2, len2);
-  cp = path + len1 + len2;
+  cp = path + len1;
   if (!IS_DIR_SEPARATOR (cp[-1]))
     *cp++ = DIR_SEPARATOR;
   *cp++ = '.';
@@ -5946,13 +5973,13 @@ is_directory (const char *path1, const c
 
   /* Exclude directories that the linker is known to search.  */
   if (linker
+      && IS_DIR_SEPARATOR (path[0])
       && ((cp - path == 6
-	   && strcmp (path, concat (dir_separator_str, "lib",
-				    dir_separator_str, ".", NULL)) == 0)
+	   && strncmp (path + 1, "lib", 3) == 0)
 	  || (cp - path == 10
-	      && strcmp (path, concat (dir_separator_str, "usr",
-				       dir_separator_str, "lib",
-				       dir_separator_str, ".", NULL)) == 0)))
+	      && strncmp (path + 1, "usr", 3) == 0
+	      && IS_DIR_SEPARATOR (path[4])
+	      && strncmp (path + 5, "lib", 3) == 0)))
     return 0;
 
   return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
@@ -6142,7 +6169,7 @@ main (int argc, const char **argv)
 			   spec_version, dir_separator_str, NULL);
   just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
 
-  specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, 0);
+  specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
   /* Read the specs file unless it is a default one.  */
   if (specs_file != 0 && strcmp (specs_file, "specs"))
     read_specs (specs_file, TRUE);
@@ -6278,7 +6305,7 @@ main (int argc, const char **argv)
   for (uptr = user_specs_head; uptr; uptr = uptr->next)
     {
       char *filename = find_a_file (&startfile_prefixes, uptr->filename,
-				    R_OK, 0);
+				    R_OK, true);
       read_specs (filename ? filename : uptr->filename, FALSE);
     }
 
@@ -6307,8 +6334,10 @@ main (int argc, const char **argv)
   if (print_search_dirs)
     {
       printf (_("install: %s%s\n"), standard_exec_prefix, machine_suffix);
-      printf (_("programs: %s\n"), build_search_list (&exec_prefixes, "", 0));
-      printf (_("libraries: %s\n"), build_search_list (&startfile_prefixes, "", 0));
+      printf (_("programs: %s\n"),
+	      build_search_list (&exec_prefixes, "", false, false));
+      printf (_("libraries: %s\n"),
+	      build_search_list (&startfile_prefixes, "", false, true));
       return (0);
     }
 
@@ -6625,14 +6654,14 @@ main (int argc, const char **argv)
       /* We'll use ld if we can't find collect2.  */
       if (! strcmp (linker_name_spec, "collect2"))
 	{
-	  char *s = find_a_file (&exec_prefixes, "collect2", X_OK, 0);
+	  char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
 	  if (s == NULL)
 	    linker_name_spec = "ld";
 	}
       /* 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_ENV);
+      putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);
+      putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV, true);
 
       value = do_spec (link_command_spec);
       if (value < 0)
openSUSE Build Service is sponsored by