diff options
author | drow <drow@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-11-22 20:01:07 +0000 |
---|---|---|
committer | drow <drow@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-11-22 20:01:07 +0000 |
commit | 5feeeb385ffdbe1125f30929aafc4b44e1f3d97d (patch) | |
tree | cd0710e42a786802096e328c11e150db4dc4067a | |
parent | 549c28fd1ce04729f5bb1617a52a2ba92e765599 (diff) | |
download | ppe42-gcc-5feeeb385ffdbe1125f30929aafc4b44e1f3d97d.tar.gz ppe42-gcc-5feeeb385ffdbe1125f30929aafc4b44e1f3d97d.zip |
include/
* libiberty.h (make_relative_prefix): Add prototype.
libiberty/
* Makefile.in: Add make-relative-prefix.c.
* make-relative-prefix.c: New file.
* functions.texi: Rebuilt.
gcc/
* gcc.c (make_relative_prefix, split_directories)
(free_split_directories): Removed.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@59385 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/gcc.c | 245 | ||||
-rw-r--r-- | include/ChangeLog | 4 | ||||
-rw-r--r-- | include/libiberty.h | 6 | ||||
-rw-r--r-- | libiberty/ChangeLog | 6 | ||||
-rw-r--r-- | libiberty/Makefile.in | 3 | ||||
-rw-r--r-- | libiberty/functions.texi | 25 | ||||
-rw-r--r-- | libiberty/make-relative-prefix.c | 387 |
8 files changed, 432 insertions, 249 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cf02ad6a463..4500b2c24ed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2002-11-22 Daniel Jacobowitz <drow@mvista.com> + * gcc.c (make_relative_prefix, split_directories) + (free_split_directories): Removed. + +2002-11-22 Daniel Jacobowitz <drow@mvista.com> + * configure.in: Set insn=nop for DWARF-2 tests on ARM. * configure: Regenerated. diff --git a/gcc/gcc.c b/gcc/gcc.c index c30851dfe17..a193437c569 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -267,11 +267,6 @@ static struct rusage rus, prus; struct path_prefix; static void init_spec PARAMS ((void)); -#ifndef VMS -static char **split_directories PARAMS ((const char *, int *)); -static void free_split_directories PARAMS ((char **)); -static char *make_relative_prefix PARAMS ((const char *, const char *, const char *)); -#endif /* VMS */ static void store_arg PARAMS ((const char *, int, int)); static char *load_specs PARAMS ((const char *)); static void read_specs PARAMS ((const char *, int)); @@ -2281,246 +2276,6 @@ putenv_from_prefixes (paths, env_var) putenv (build_search_list (paths, env_var, 1)); } -#ifndef VMS - -/* FIXME: the location independence code for VMS is hairier than this, - and hasn't been written. */ - -/* Split a filename into component directories. */ - -static char ** -split_directories (name, ptr_num_dirs) - const char *name; - int *ptr_num_dirs; -{ - int num_dirs = 0; - char **dirs; - const char *p, *q; - int ch; - - /* Count the number of directories. Special case MSDOS disk names as part - of the initial directory. */ - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - p += 3; - num_dirs++; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - num_dirs++; - while (IS_DIR_SEPARATOR (*p)) - p++; - } - } - - dirs = (char **) xmalloc (sizeof (char *) * (num_dirs + 2)); - - /* Now copy the directory parts. */ - num_dirs = 0; - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - dirs[num_dirs++] = save_string (p, 3); - p += 3; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - q = p; - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - while (IS_DIR_SEPARATOR (*p)) - p++; - - dirs[num_dirs++] = save_string (q, p - q); - q = p; - } - } - - if (p - 1 - q > 0) - dirs[num_dirs++] = save_string (q, p - 1 - q); - - dirs[num_dirs] = NULL; - if (ptr_num_dirs) - *ptr_num_dirs = num_dirs; - - return dirs; -} - -/* Release storage held by split directories. */ - -static void -free_split_directories (dirs) - char **dirs; -{ - int i = 0; - - while (dirs[i] != NULL) - free (dirs[i++]); - - free ((char *) dirs); -} - -/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets - to PREFIX starting with the directory portion of PROGNAME and a relative - pathname of the difference between BIN_PREFIX and PREFIX. - - For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is - /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this - function will return /red/green/blue/../omega. - - If no relative prefix can be found, return NULL. */ - -static char * -make_relative_prefix (progname, bin_prefix, prefix) - const char *progname; - const char *bin_prefix; - const char *prefix; -{ - char **prog_dirs, **bin_dirs, **prefix_dirs; - int prog_num, bin_num, prefix_num, std_loc_p; - int i, n, common; - - prog_dirs = split_directories (progname, &prog_num); - bin_dirs = split_directories (bin_prefix, &bin_num); - - /* 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) - { - char *temp; - - GET_ENVIRONMENT (temp, "PATH"); - if (temp) - { - char *startp, *endp, *nstore; - size_t prefixlen = strlen (temp) + 1; - if (prefixlen < 2) - prefixlen = 2; - - nstore = (char *) alloca (prefixlen + strlen (progname) + 1); - - startp = endp = temp; - while (1) - { - if (*endp == PATH_SEPARATOR || *endp == 0) - { - if (endp == startp) - { - nstore[0] = '.'; - nstore[1] = DIR_SEPARATOR; - nstore[2] = '\0'; - } - else - { - strncpy (nstore, startp, endp - startp); - if (! IS_DIR_SEPARATOR (endp[-1])) - { - nstore[endp - startp] = DIR_SEPARATOR; - nstore[endp - startp + 1] = 0; - } - else - nstore[endp - startp] = 0; - } - strcat (nstore, progname); - if (! access (nstore, X_OK) -#ifdef HAVE_HOST_EXECUTABLE_SUFFIX - || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) -#endif - ) - { - free_split_directories (prog_dirs); - progname = nstore; - prog_dirs = split_directories (progname, &prog_num); - break; - } - - if (*endp == 0) - break; - endp = startp = endp + 1; - } - else - endp++; - } - } - } - - /* Remove the program name from comparison of directory names. */ - prog_num--; - - /* Determine if the compiler is installed in the standard location, and if - so, we don't need to specify relative directories. Also, if argv[0] - doesn't contain any directory specifiers, there is not much we can do. */ - std_loc_p = 0; - if (prog_num == bin_num) - { - for (i = 0; i < bin_num; i++) - { - if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) - break; - } - - if (prog_num <= 0 || i == bin_num) - { - std_loc_p = 1; - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - prog_dirs = bin_dirs = (char **) 0; - return NULL; - } - } - - prefix_dirs = split_directories (prefix, &prefix_num); - - /* Find how many directories are in common between bin_prefix & prefix. */ - n = (prefix_num < bin_num) ? prefix_num : bin_num; - for (common = 0; common < n; common++) - { - if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) - break; - } - - /* 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; - } - - /* Build up the pathnames in argv[0]. */ - for (i = 0; i < prog_num; i++) - obstack_grow (&obstack, prog_dirs[i], strlen (prog_dirs[i])); - - /* Now build up the ..'s. */ - for (i = common; i < n; i++) - { - obstack_grow (&obstack, DIR_UP, sizeof (DIR_UP) - 1); - obstack_1grow (&obstack, DIR_SEPARATOR); - } - - /* Put in directories to move over to prefix. */ - for (i = common; i < prefix_num; i++) - obstack_grow (&obstack, prefix_dirs[i], strlen (prefix_dirs[i])); - - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - free_split_directories (prefix_dirs); - - obstack_1grow (&obstack, '\0'); - return obstack_finish (&obstack); -} -#endif /* VMS */ - /* Check whether NAME can be accessed in MODE. This is like access, except that it never considers directories to be executable. */ diff --git a/include/ChangeLog b/include/ChangeLog index 2eaa1fd2d69..ea9575351f5 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2002-11-22 Daniel Jacobowitz <drow@mvista.com> + + * libiberty.h (make_relative_prefix): Add prototype. + 2002-10-26 Roger Sayle <roger@eyesopen.com> * partition.h: Close the extern "C" scope when compiling with C++. diff --git a/include/libiberty.h b/include/libiberty.h index 983fd96e5ae..c02e035e3af 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -145,6 +145,12 @@ extern char * getpwd PARAMS ((void)); extern long get_run_time PARAMS ((void)); +/* Generate a relocated path to some installation directory. Allocates + return value using malloc. */ + +extern char *make_relative_prefix PARAMS ((const char *, const char *, + const char *)); + /* Choose a temporary directory to use for scratch files. */ extern char *choose_temp_base PARAMS ((void)) ATTRIBUTE_MALLOC; diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 8966e2ee867..57ff7da31b5 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,9 @@ +2002-11-22 Daniel Jacobowitz <drow@mvista.com> + + * Makefile.in: Add make-relative-prefix.c. + * make-relative-prefix.c: New file. + * functions.texi: Rebuilt. + 2002-11-16 Jakub Jelinek <jakub@redhat.com> * md5.c (md5_process_block): Avoid `function-like macro "F{G,H,I}" must be diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in index e0bb15a7519..cdf14a4311b 100644 --- a/libiberty/Makefile.in +++ b/libiberty/Makefile.in @@ -135,6 +135,7 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \ hashtab.c hex.c \ index.c insque.c \ lbasename.c \ + make-relative-prefix.c \ make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c \ memset.c mkstemps.c \ objalloc.c obstack.c \ @@ -159,6 +160,7 @@ REQUIRED_OFILES = regex.o cplus-dem.o cp-demangle.o md5.o \ getopt.o getopt1.o getpwd.o getruntime.o \ hashtab.o hex.o \ lbasename.o \ + make-relative-prefix.o \ make-temp-file.o \ objalloc.o obstack.o \ partition.o pexecute.o \ @@ -432,6 +434,7 @@ hashtab.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/hashtab.h \ hex.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h lbasename.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ $(INCDIR)/safe-ctype.h +make-relative-prefix.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h make-temp-file.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h md5.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/md5.h memchr.o: $(INCDIR)/ansidecl.h diff --git a/libiberty/functions.texi b/libiberty/functions.texi index b518243d95a..7d9c181d219 100644 --- a/libiberty/functions.texi +++ b/libiberty/functions.texi @@ -276,7 +276,7 @@ itself. @end deftypefn -@c getruntime.c:78 +@c getruntime.c:82 @deftypefn Replacement long get_run_time (void) Returns the time used so far, in microseconds. If possible, this is @@ -322,11 +322,12 @@ between calls to @code{getpwd}. Initializes the array mapping the current character set to corresponding hex values. This function must be called before any -call to @code{hex_p} or @code{hex_value}. +call to @code{hex_p} or @code{hex_value}. If you fail to call it, a +default ASCII-based table will normally be used on ASCII systems. @end deftypefn -@c hex.c:33 +@c hex.c:34 @deftypefn Extension int hex_p (int @var{c}) Evaluates to non-zero if the given character is a valid hex character, @@ -335,7 +336,7 @@ or zero if it is not. Note that the value you pass will be cast to @end deftypefn -@c hex.c:41 +@c hex.c:42 @deftypefn Extension int hex_value (int @var{c}) Returns the numeric equivalent of the given character when interpreted @@ -391,6 +392,22 @@ and a path ending in @code{/} returns the empty string after it. @end deftypefn +@c make-relative-prefix.c:24 +@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}. + +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 + @c make-temp-file.c:138 @deftypefn Replacement char* make_temp_file (const char *@var{suffix}) diff --git a/libiberty/make-relative-prefix.c b/libiberty/make-relative-prefix.c new file mode 100644 index 00000000000..ae1ac54295a --- /dev/null +++ b/libiberty/make-relative-prefix.c @@ -0,0 +1,387 @@ +/* Relative (relocatable) prefix support. + Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +This file is part of libiberty. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +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. */ + +/* + +@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}. + +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 + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <string.h> + +#include "ansidecl.h" +#include "libiberty.h" + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) \ + || defined (__DJGPP__) || defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define HOST_EXECUTABLE_SUFFIX ".exe" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# define PATH_SEPARATOR ';' +#else +# define PATH_SEPARATOR ':' +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif + +#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 (s, len) + const char *s; + int len; +{ + char *result = malloc (len + 1); + + memcpy (result, s, len); + result[len] = 0; + return result; +} + +/* Split a filename into component directories. */ + +static char ** +split_directories (name, ptr_num_dirs) + const char *name; + int *ptr_num_dirs; +{ + int num_dirs = 0; + char **dirs; + const char *p, *q; + int ch; + + /* Count the number of directories. Special case MSDOS disk names as part + of the initial directory. */ + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + p += 3; + num_dirs++; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + num_dirs++; + while (IS_DIR_SEPARATOR (*p)) + p++; + } + } + + dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); + if (dirs == NULL) + return NULL; + + /* Now copy the directory parts. */ + num_dirs = 0; + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + dirs[num_dirs++] = save_string (p, 3); + if (dirs[num_dirs - 1] == NULL) + { + free (dirs); + return NULL; + } + p += 3; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + q = p; + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + while (IS_DIR_SEPARATOR (*p)) + p++; + + dirs[num_dirs++] = save_string (q, p - q); + if (dirs[num_dirs - 1] == NULL) + { + dirs[num_dirs] = NULL; + free_split_directories (dirs); + return NULL; + } + q = p; + } + } + + if (p - 1 - q > 0) + dirs[num_dirs++] = save_string (q, p - 1 - q); + dirs[num_dirs] = NULL; + + if (dirs[num_dirs - 1] == NULL) + { + free_split_directories (dirs); + return NULL; + } + + if (ptr_num_dirs) + *ptr_num_dirs = num_dirs; + return dirs; +} + +/* Release storage held by split directories. */ + +static void +free_split_directories (dirs) + char **dirs; +{ + int i = 0; + + while (dirs[i] != NULL) + free (dirs[i++]); + + free ((char *) dirs); +} + +/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets + to PREFIX starting with the directory portion of PROGNAME and a relative + pathname of the difference between BIN_PREFIX and PREFIX. + + For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is + /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this + function will return /red/green/blue/../../omega/. + + 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; +{ + char **prog_dirs, **bin_dirs, **prefix_dirs; + int prog_num, bin_num, prefix_num; + int i, n, common; + int needed_len; + char *ret, *ptr; + + 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) + { + char *temp; + + temp = getenv ("PATH"); + if (temp) + { + char *startp, *endp, *nstore; + size_t prefixlen = strlen (temp) + 1; + if (prefixlen < 2) + prefixlen = 2; + + nstore = (char *) alloca (prefixlen + strlen (progname) + 1); + + startp = endp = temp; + while (1) + { + if (*endp == PATH_SEPARATOR || *endp == 0) + { + if (endp == startp) + { + nstore[0] = '.'; + nstore[1] = DIR_SEPARATOR; + nstore[2] = '\0'; + } + else + { + strncpy (nstore, startp, endp - startp); + if (! IS_DIR_SEPARATOR (endp[-1])) + { + nstore[endp - startp] = DIR_SEPARATOR; + nstore[endp - startp + 1] = 0; + } + else + nstore[endp - startp] = 0; + } + strcat (nstore, progname); + if (! access (nstore, X_OK) +#ifdef HAVE_HOST_EXECUTABLE_SUFFIX + || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) +#endif + ) + { + free_split_directories (prog_dirs); + progname = nstore; + prog_dirs = split_directories (progname, &prog_num); + if (prog_dirs == NULL) + { + free_split_directories (bin_dirs); + return NULL; + } + break; + } + + if (*endp == 0) + break; + endp = startp = endp + 1; + } + else + endp++; + } + } + } + + /* Remove the program name from comparison of directory names. */ + prog_num--; + + /* If we are still installed in the standard location, we don't need to + specify relative directories. Also, if argv[0] still doesn't contain + any directory specifiers after the search above, then there is not much + we can do. */ + if (prog_num == bin_num) + { + for (i = 0; i < bin_num; i++) + { + if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) + break; + } + + 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; + } + } + + prefix_dirs = split_directories (prefix, &prefix_num); + if (prefix_dirs == NULL) + { + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + return NULL; + } + + /* Find how many directories are in common between bin_prefix & prefix. */ + n = (prefix_num < bin_num) ? prefix_num : bin_num; + for (common = 0; common < n; common++) + { + if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) + break; + } + + /* 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; + } + + /* Two passes: first figure out the size of the result string, and + then construct it. */ + needed_len = 0; + for (i = 0; i < prog_num; i++) + needed_len += strlen (prog_dirs[i]); + needed_len += sizeof (DIR_UP) * (bin_num - common); + for (i = common; i < prefix_num; i++) + needed_len += strlen (prefix_dirs[i]); + needed_len += 1; /* Trailing NUL. */ + + ret = (char *) malloc (needed_len); + if (ret == NULL) + return NULL; + + /* Build up the pathnames in argv[0]. */ + for (i = 0; i < prog_num; i++) + strcat (ret, prog_dirs[i]); + + /* Now build up the ..'s. */ + ptr = ret + strlen(ret); + for (i = common; i < bin_num; i++) + { + strcpy (ptr, DIR_UP); + ptr += sizeof (DIR_UP) - 1; + *(ptr++) = DIR_SEPARATOR; + } + *ptr = '\0'; + + /* Put in directories to move over to prefix. */ + for (i = common; i < prefix_num; i++) + strcat (ret, prefix_dirs[i]); + + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + free_split_directories (prefix_dirs); + + return ret; +} |