gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / libiberty / make-relative-prefix.c
index 883d92b1458ed4dbe97ba822e817ea437569db30..e3f9f920df4a2b4a8be00e88727d74a42ed46eea 100644 (file)
@@ -1,6 +1,5 @@
 /* Relative (relocatable) prefix support.
-   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of libiberty.
 
@@ -21,7 +20,8 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
 
 /*
 
-@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix})
+@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, @
+  const char *@var{bin_prefix}, const char *@var{prefix})
 
 Given three paths @var{progname}, @var{bin_prefix}, @var{prefix},
 return the path that is in the same position relative to
@@ -57,6 +57,9 @@ relative prefix can be found, return @code{NULL}.
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
 #include <string.h>
 
@@ -102,7 +105,7 @@ static void free_split_directories (char **);
 static char *
 save_string (const char *s, int len)
 {
-  char *result = malloc (len + 1);
+  char *result = (char *) malloc (len + 1);
 
   memcpy (result, s, len);
   result[len] = 0;
@@ -119,6 +122,9 @@ split_directories (const char *name, int *ptr_num_dirs)
   const char *p, *q;
   int ch;
 
+  if (!*name)
+    return NULL;
+
   /* Count the number of directories.  Special case MSDOS disk names as part
      of the initial directory.  */
   p = name;
@@ -201,10 +207,13 @@ free_split_directories (char **dirs)
 {
   int i = 0;
 
-  while (dirs[i] != NULL)
-    free (dirs[i++]);
+  if (dirs != NULL)
+    {
+      while (dirs[i] != NULL)
+       free (dirs[i++]);
 
-  free ((char *) dirs);
+      free ((char *) dirs);
+    }
 }
 
 /* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
@@ -217,15 +226,16 @@ free_split_directories (char **dirs)
 
    If no relative prefix can be found, return NULL.  */
 
-char *
-make_relative_prefix (const char *progname,
-                      const char *bin_prefix, const char *prefix)
+static char *
+make_relative_prefix_1 (const char *progname, const char *bin_prefix,
+                       const char *prefix, const int resolve_links)
 {
-  char **prog_dirs, **bin_dirs, **prefix_dirs;
+  char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
   int prog_num, bin_num, prefix_num;
   int i, n, common;
   int needed_len;
-  char *ret, *ptr, *full_progname = NULL;
+  char *ret = NULL, *ptr, *full_progname;
+  char *alloc_ptr = NULL;
 
   if (progname == NULL || bin_prefix == NULL || prefix == NULL)
     return NULL;
@@ -241,10 +251,18 @@ make_relative_prefix (const char *progname,
        {
          char *startp, *endp, *nstore;
          size_t prefixlen = strlen (temp) + 1;
+         size_t len;
          if (prefixlen < 2)
            prefixlen = 2;
 
-         nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
+         len = prefixlen + strlen (progname) + 1;
+#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
+         len += strlen (HOST_EXECUTABLE_SUFFIX);
+#endif
+         if (len < MAX_ALLOCA_SIZE)
+           nstore = (char *) alloca (len);
+         else
+           alloc_ptr = nstore = (char *) malloc (len);
 
          startp = endp = temp;
          while (1)
@@ -259,7 +277,7 @@ make_relative_prefix (const char *progname,
                    }
                  else
                    {
-                     strncpy (nstore, startp, endp - startp);
+                     memcpy (nstore, startp, endp - startp);
                      if (! IS_DIR_SEPARATOR (endp[-1]))
                        {
                          nstore[endp - startp] = DIR_SEPARATOR;
@@ -275,8 +293,14 @@ make_relative_prefix (const char *progname,
 #endif
                      )
                    {
-                     progname = nstore;
-                     break;
+#if defined (HAVE_SYS_STAT_H) && defined (S_ISREG)
+                     struct stat st;
+                     if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode))
+#endif
+                       {
+                         progname = nstore;
+                         break;
+                       }
                    }
 
                  if (*endp == 0)
@@ -289,15 +313,21 @@ make_relative_prefix (const char *progname,
        }
     }
 
-  full_progname = lrealpath (progname);
+  if (resolve_links)
+    full_progname = lrealpath (progname);
+  else
+    full_progname = strdup (progname);
   if (full_progname == NULL)
-    return NULL;
+    goto bailout;
 
   prog_dirs = split_directories (full_progname, &prog_num);
-  bin_dirs = split_directories (bin_prefix, &bin_num);
   free (full_progname);
-  if (bin_dirs == NULL || prog_dirs == NULL)
-    return NULL;
+  if (prog_dirs == NULL)
+    goto bailout;
+
+  bin_dirs = split_directories (bin_prefix, &bin_num);
+  if (bin_dirs == NULL)
+    goto bailout;
 
   /* Remove the program name from comparison of directory names.  */
   prog_num--;
@@ -315,21 +345,12 @@ make_relative_prefix (const char *progname,
        }
 
       if (prog_num <= 0 || i == bin_num)
-       {
-         free_split_directories (prog_dirs);
-         free_split_directories (bin_dirs);
-         prog_dirs = bin_dirs = (char **) 0;
-         return NULL;
-       }
+       goto bailout;
     }
 
   prefix_dirs = split_directories (prefix, &prefix_num);
   if (prefix_dirs == NULL)
-    {
-      free_split_directories (prog_dirs);
-      free_split_directories (bin_dirs);
-      return NULL;
-    }
+    goto bailout;
 
   /* Find how many directories are in common between bin_prefix & prefix.  */
   n = (prefix_num < bin_num) ? prefix_num : bin_num;
@@ -341,12 +362,7 @@ make_relative_prefix (const char *progname,
 
   /* If there are no common directories, there can be no relative prefix.  */
   if (common == 0)
-    {
-      free_split_directories (prog_dirs);
-      free_split_directories (bin_dirs);
-      free_split_directories (prefix_dirs);
-      return NULL;
-    }
+    goto bailout;
 
   /* Two passes: first figure out the size of the result string, and
      then construct it.  */
@@ -360,7 +376,7 @@ make_relative_prefix (const char *progname,
 
   ret = (char *) malloc (needed_len);
   if (ret == NULL)
-    return NULL;
+    goto bailout;
 
   /* Build up the pathnames in argv[0].  */
   *ret = '\0';
@@ -381,9 +397,38 @@ make_relative_prefix (const char *progname,
   for (i = common; i < prefix_num; i++)
     strcat (ret, prefix_dirs[i]);
 
+ bailout:
   free_split_directories (prog_dirs);
   free_split_directories (bin_dirs);
   free_split_directories (prefix_dirs);
+  free (alloc_ptr);
 
   return ret;
 }
+
+
+/* Do the full job, including symlink resolution.
+   This path will find files installed in the same place as the
+   program even when a soft link has been made to the program
+   from somwhere else. */
+
+char *
+make_relative_prefix (const char *progname, const char *bin_prefix,
+                     const char *prefix)
+{
+  return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
+}
+
+/* Make the relative pathname without attempting to resolve any links.
+   '..' etc may also be left in the pathname.
+   This will find the files the user meant the program to find if the
+   installation is patched together with soft links. */
+
+char *
+make_relative_prefix_ignore_links (const char *progname,
+                                  const char *bin_prefix,
+                                  const char *prefix)
+{
+  return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
+}
+
This page took 0.04639 seconds and 4 git commands to generate.