X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=libiberty%2Fmake-relative-prefix.c;h=eebcff9957e357f124e46841e1b7cf2c7368d9d6;hb=e66cfcef729d758a5e605d57600530ad9b1bb9c3;hp=ef9177e9c93c108a0535bfb3b825722f338dba54;hpb=756954c3c911ad904623426b5631436511b95cca;p=deliverable%2Fbinutils-gdb.git diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c index ef9177e9c9..eebcff9957 100644 --- a/libiberty/make-relative-prefix.c +++ b/libiberty/make-relative-prefix.c @@ -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-2018 Free Software Foundation, Inc. This file is part of libiberty. @@ -16,23 +15,33 @@ 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. */ /* -@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 strings @var{progname}, @var{bin_prefix}, @var{prefix}, return a string -that gets to @var{prefix} starting with the directory portion of @var{progname} and -a relative pathname of the difference between @var{bin_prefix} and @var{prefix}. +Given three paths @var{progname}, @var{bin_prefix}, @var{prefix}, +return the path that is in the same position relative to +@var{progname}'s directory as @var{prefix} is relative to +@var{bin_prefix}. That is, a string starting with the directory +portion of @var{progname}, followed by a relative pathname of the +difference between @var{bin_prefix} and @var{prefix}. -For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, @var{prefix} -is @code{/alpha/beta/gamma/omega/}, and @var{progname} is @code{/red/green/blue/gcc}, -then this function will return @code{/red/green/blue/../../omega/}. +If @var{progname} does not contain any directory separators, +@code{make_relative_prefix} will search @env{PATH} to find a program +named @var{progname}. Also, if @var{progname} is a symbolic link, +the symbolic link will be resolved. -The return value is normally allocated via @code{malloc}. If no relative prefix -can be found, return @code{NULL}. +For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, +@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is +@code{/red/green/blue/gcc}, then this function will return +@code{/red/green/blue/../../omega/}. + +The return value is normally allocated via @code{malloc}. If no +relative prefix can be found, return @code{NULL}. @end deftypefn @@ -48,6 +57,9 @@ can be found, return @code{NULL}. #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_SYS_STAT_H +#include +#endif #include @@ -67,6 +79,7 @@ can be found, return @code{NULL}. #if defined (_WIN32) || defined (__MSDOS__) \ || defined (__DJGPP__) || defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM +# define HAVE_HOST_EXECUTABLE_SUFFIX # define HOST_EXECUTABLE_SUFFIX ".exe" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' @@ -85,16 +98,14 @@ 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; @@ -104,9 +115,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; @@ -191,15 +200,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 @@ -212,29 +223,23 @@ 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; + char *ret = NULL, *ptr, *full_progname; + char *alloc_ptr = NULL; if (progname == NULL || bin_prefix == NULL || prefix == NULL) return NULL; - prog_dirs = split_directories (progname, &prog_num); - bin_dirs = split_directories (bin_prefix, &bin_num); - if (bin_dirs == NULL || prog_dirs == NULL) - return NULL; - /* If there is no full pathname, try to find the program by checking in each of the directories specified in the PATH environment variable. */ - if (prog_num == 1) + if (lbasename (progname) == progname) { char *temp; @@ -243,10 +248,18 @@ make_relative_prefix (progname, bin_prefix, prefix) { 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) @@ -261,7 +274,7 @@ make_relative_prefix (progname, bin_prefix, prefix) } else { - strncpy (nstore, startp, endp - startp); + memcpy (nstore, startp, endp - startp); if (! IS_DIR_SEPARATOR (endp[-1])) { nstore[endp - startp] = DIR_SEPARATOR; @@ -277,15 +290,14 @@ make_relative_prefix (progname, bin_prefix, prefix) #endif ) { - free_split_directories (prog_dirs); - progname = nstore; - prog_dirs = split_directories (progname, &prog_num); - if (prog_dirs == NULL) +#if defined (HAVE_SYS_STAT_H) && defined (S_ISREG) + struct stat st; + if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode)) +#endif { - free_split_directories (bin_dirs); - return NULL; + progname = nstore; + break; } - break; } if (*endp == 0) @@ -298,6 +310,22 @@ make_relative_prefix (progname, bin_prefix, prefix) } } + if (resolve_links) + full_progname = lrealpath (progname); + else + full_progname = strdup (progname); + if (full_progname == NULL) + goto bailout; + + prog_dirs = split_directories (full_progname, &prog_num); + free (full_progname); + 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--; @@ -314,21 +342,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; @@ -340,12 +359,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. */ @@ -359,7 +373,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'; @@ -380,9 +394,38 @@ 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); + 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); +} +