OSDN Git Service

libgcc/
[pf3gnuchains/gcc-fork.git] / libiberty / make-relative-prefix.c
index dc4f8d5..c98d287 100644 (file)
@@ -1,6 +1,6 @@
 /* Relative (relocatable) prefix support.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
 
 This file is part of libiberty.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /*
 
@@ -95,16 +95,14 @@ relative prefix can be found, return @code{NULL}.
 
 #define DIR_UP ".."
 
-static char *save_string PARAMS ((const char *, int));
-static char **split_directories        PARAMS ((const char *, int *));
-static void free_split_directories PARAMS ((char **));
+static char *save_string (const char *, int);
+static char **split_directories        (const char *, int *);
+static void free_split_directories (char **);
 
 static char *
-save_string (s, len)
-     const char *s;
-     int len;
+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;
@@ -114,9 +112,7 @@ save_string (s, len)
 /* Split a filename into component directories.  */
 
 static char **
-split_directories (name, ptr_num_dirs)
-     const char *name;
-     int *ptr_num_dirs;
+split_directories (const char *name, int *ptr_num_dirs)
 {
   int num_dirs = 0;
   char **dirs;
@@ -201,15 +197,17 @@ split_directories (name, ptr_num_dirs)
 /* Release storage held by split directories.  */
 
 static void
-free_split_directories (dirs)
-     char **dirs;
+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
@@ -222,17 +220,15 @@ free_split_directories (dirs)
 
    If no relative prefix can be found, return NULL.  */
 
-char *
-make_relative_prefix (progname, bin_prefix, 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;
 
   if (progname == NULL || bin_prefix == NULL || prefix == NULL)
     return NULL;
@@ -296,16 +292,22 @@ make_relative_prefix (progname, bin_prefix, prefix)
        }
     }
 
-  full_progname = lrealpath (progname);
+  if (resolve_links)
+    full_progname = lrealpath (progname);
+  else
+    full_progname = strdup (progname);
   if (full_progname == NULL)
     return NULL;
 
   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)
+  if (prog_dirs == NULL)
     return NULL;
 
+  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--;
 
@@ -322,21 +324,12 @@ make_relative_prefix (progname, bin_prefix, prefix)
        }
 
       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;
@@ -348,12 +341,7 @@ make_relative_prefix (progname, bin_prefix, prefix)
 
   /* 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.  */
@@ -367,7 +355,7 @@ make_relative_prefix (progname, bin_prefix, prefix)
 
   ret = (char *) malloc (needed_len);
   if (ret == NULL)
-    return NULL;
+    goto bailout;
 
   /* Build up the pathnames in argv[0].  */
   *ret = '\0';
@@ -388,9 +376,37 @@ make_relative_prefix (progname, bin_prefix, prefix)
   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);
 
   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);
+}
+