xref: /dflybsd-src/contrib/gdb-7/libiberty/make-relative-prefix.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
15796c8dcSSimon Schubert /* Relative (relocatable) prefix support.
25796c8dcSSimon Schubert    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3*ef5ccd6cSJohn Marino    1999, 2000, 2001, 2002, 2006, 2012 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert This file is part of libiberty.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert GCC is free software; you can redistribute it and/or modify it under
85796c8dcSSimon Schubert the terms of the GNU General Public License as published by the Free
95796c8dcSSimon Schubert Software Foundation; either version 2, or (at your option) any later
105796c8dcSSimon Schubert version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert GCC is distributed in the hope that it will be useful, but WITHOUT ANY
135796c8dcSSimon Schubert WARRANTY; without even the implied warranty of MERCHANTABILITY or
145796c8dcSSimon Schubert FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
155796c8dcSSimon Schubert for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert along with GCC; see the file COPYING.  If not, write to the Free
195796c8dcSSimon Schubert Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
205796c8dcSSimon Schubert 02110-1301, USA.  */
215796c8dcSSimon Schubert 
225796c8dcSSimon Schubert /*
235796c8dcSSimon Schubert 
24c50c785cSJohn Marino @deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, @
25c50c785cSJohn Marino   const char *@var{bin_prefix}, const char *@var{prefix})
265796c8dcSSimon Schubert 
275796c8dcSSimon Schubert Given three paths @var{progname}, @var{bin_prefix}, @var{prefix},
285796c8dcSSimon Schubert return the path that is in the same position relative to
295796c8dcSSimon Schubert @var{progname}'s directory as @var{prefix} is relative to
305796c8dcSSimon Schubert @var{bin_prefix}.  That is, a string starting with the directory
315796c8dcSSimon Schubert portion of @var{progname}, followed by a relative pathname of the
325796c8dcSSimon Schubert difference between @var{bin_prefix} and @var{prefix}.
335796c8dcSSimon Schubert 
345796c8dcSSimon Schubert If @var{progname} does not contain any directory separators,
355796c8dcSSimon Schubert @code{make_relative_prefix} will search @env{PATH} to find a program
365796c8dcSSimon Schubert named @var{progname}.  Also, if @var{progname} is a symbolic link,
375796c8dcSSimon Schubert the symbolic link will be resolved.
385796c8dcSSimon Schubert 
395796c8dcSSimon Schubert For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta},
405796c8dcSSimon Schubert @var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is
415796c8dcSSimon Schubert @code{/red/green/blue/gcc}, then this function will return
425796c8dcSSimon Schubert @code{/red/green/blue/../../omega/}.
435796c8dcSSimon Schubert 
445796c8dcSSimon Schubert The return value is normally allocated via @code{malloc}.  If no
455796c8dcSSimon Schubert relative prefix can be found, return @code{NULL}.
465796c8dcSSimon Schubert 
475796c8dcSSimon Schubert @end deftypefn
485796c8dcSSimon Schubert 
495796c8dcSSimon Schubert */
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert #ifdef HAVE_CONFIG_H
525796c8dcSSimon Schubert #include "config.h"
535796c8dcSSimon Schubert #endif
545796c8dcSSimon Schubert 
555796c8dcSSimon Schubert #ifdef HAVE_STDLIB_H
565796c8dcSSimon Schubert #include <stdlib.h>
575796c8dcSSimon Schubert #endif
585796c8dcSSimon Schubert #ifdef HAVE_UNISTD_H
595796c8dcSSimon Schubert #include <unistd.h>
605796c8dcSSimon Schubert #endif
61*ef5ccd6cSJohn Marino #ifdef HAVE_SYS_STAT_H
62*ef5ccd6cSJohn Marino #include <sys/stat.h>
63*ef5ccd6cSJohn Marino #endif
645796c8dcSSimon Schubert 
655796c8dcSSimon Schubert #include <string.h>
665796c8dcSSimon Schubert 
675796c8dcSSimon Schubert #include "ansidecl.h"
685796c8dcSSimon Schubert #include "libiberty.h"
695796c8dcSSimon Schubert 
705796c8dcSSimon Schubert #ifndef R_OK
715796c8dcSSimon Schubert #define R_OK 4
725796c8dcSSimon Schubert #define W_OK 2
735796c8dcSSimon Schubert #define X_OK 1
745796c8dcSSimon Schubert #endif
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert #ifndef DIR_SEPARATOR
775796c8dcSSimon Schubert #  define DIR_SEPARATOR '/'
785796c8dcSSimon Schubert #endif
795796c8dcSSimon Schubert 
805796c8dcSSimon Schubert #if defined (_WIN32) || defined (__MSDOS__) \
815796c8dcSSimon Schubert     || defined (__DJGPP__) || defined (__OS2__)
825796c8dcSSimon Schubert #  define HAVE_DOS_BASED_FILE_SYSTEM
835796c8dcSSimon Schubert #  define HAVE_HOST_EXECUTABLE_SUFFIX
845796c8dcSSimon Schubert #  define HOST_EXECUTABLE_SUFFIX ".exe"
855796c8dcSSimon Schubert #  ifndef DIR_SEPARATOR_2
865796c8dcSSimon Schubert #    define DIR_SEPARATOR_2 '\\'
875796c8dcSSimon Schubert #  endif
885796c8dcSSimon Schubert #  define PATH_SEPARATOR ';'
895796c8dcSSimon Schubert #else
905796c8dcSSimon Schubert #  define PATH_SEPARATOR ':'
915796c8dcSSimon Schubert #endif
925796c8dcSSimon Schubert 
935796c8dcSSimon Schubert #ifndef DIR_SEPARATOR_2
945796c8dcSSimon Schubert #  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
955796c8dcSSimon Schubert #else
965796c8dcSSimon Schubert #  define IS_DIR_SEPARATOR(ch) \
975796c8dcSSimon Schubert 	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
985796c8dcSSimon Schubert #endif
995796c8dcSSimon Schubert 
1005796c8dcSSimon Schubert #define DIR_UP ".."
1015796c8dcSSimon Schubert 
1025796c8dcSSimon Schubert static char *save_string (const char *, int);
1035796c8dcSSimon Schubert static char **split_directories	(const char *, int *);
1045796c8dcSSimon Schubert static void free_split_directories (char **);
1055796c8dcSSimon Schubert 
1065796c8dcSSimon Schubert static char *
save_string(const char * s,int len)1075796c8dcSSimon Schubert save_string (const char *s, int len)
1085796c8dcSSimon Schubert {
1095796c8dcSSimon Schubert   char *result = (char *) malloc (len + 1);
1105796c8dcSSimon Schubert 
1115796c8dcSSimon Schubert   memcpy (result, s, len);
1125796c8dcSSimon Schubert   result[len] = 0;
1135796c8dcSSimon Schubert   return result;
1145796c8dcSSimon Schubert }
1155796c8dcSSimon Schubert 
1165796c8dcSSimon Schubert /* Split a filename into component directories.  */
1175796c8dcSSimon Schubert 
1185796c8dcSSimon Schubert static char **
split_directories(const char * name,int * ptr_num_dirs)1195796c8dcSSimon Schubert split_directories (const char *name, int *ptr_num_dirs)
1205796c8dcSSimon Schubert {
1215796c8dcSSimon Schubert   int num_dirs = 0;
1225796c8dcSSimon Schubert   char **dirs;
1235796c8dcSSimon Schubert   const char *p, *q;
1245796c8dcSSimon Schubert   int ch;
1255796c8dcSSimon Schubert 
1265796c8dcSSimon Schubert   /* Count the number of directories.  Special case MSDOS disk names as part
1275796c8dcSSimon Schubert      of the initial directory.  */
1285796c8dcSSimon Schubert   p = name;
1295796c8dcSSimon Schubert #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1305796c8dcSSimon Schubert   if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
1315796c8dcSSimon Schubert     {
1325796c8dcSSimon Schubert       p += 3;
1335796c8dcSSimon Schubert       num_dirs++;
1345796c8dcSSimon Schubert     }
1355796c8dcSSimon Schubert #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
1365796c8dcSSimon Schubert 
1375796c8dcSSimon Schubert   while ((ch = *p++) != '\0')
1385796c8dcSSimon Schubert     {
1395796c8dcSSimon Schubert       if (IS_DIR_SEPARATOR (ch))
1405796c8dcSSimon Schubert 	{
1415796c8dcSSimon Schubert 	  num_dirs++;
1425796c8dcSSimon Schubert 	  while (IS_DIR_SEPARATOR (*p))
1435796c8dcSSimon Schubert 	    p++;
1445796c8dcSSimon Schubert 	}
1455796c8dcSSimon Schubert     }
1465796c8dcSSimon Schubert 
1475796c8dcSSimon Schubert   dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
1485796c8dcSSimon Schubert   if (dirs == NULL)
1495796c8dcSSimon Schubert     return NULL;
1505796c8dcSSimon Schubert 
1515796c8dcSSimon Schubert   /* Now copy the directory parts.  */
1525796c8dcSSimon Schubert   num_dirs = 0;
1535796c8dcSSimon Schubert   p = name;
1545796c8dcSSimon Schubert #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1555796c8dcSSimon Schubert   if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
1565796c8dcSSimon Schubert     {
1575796c8dcSSimon Schubert       dirs[num_dirs++] = save_string (p, 3);
1585796c8dcSSimon Schubert       if (dirs[num_dirs - 1] == NULL)
1595796c8dcSSimon Schubert 	{
1605796c8dcSSimon Schubert 	  free (dirs);
1615796c8dcSSimon Schubert 	  return NULL;
1625796c8dcSSimon Schubert 	}
1635796c8dcSSimon Schubert       p += 3;
1645796c8dcSSimon Schubert     }
1655796c8dcSSimon Schubert #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
1665796c8dcSSimon Schubert 
1675796c8dcSSimon Schubert   q = p;
1685796c8dcSSimon Schubert   while ((ch = *p++) != '\0')
1695796c8dcSSimon Schubert     {
1705796c8dcSSimon Schubert       if (IS_DIR_SEPARATOR (ch))
1715796c8dcSSimon Schubert 	{
1725796c8dcSSimon Schubert 	  while (IS_DIR_SEPARATOR (*p))
1735796c8dcSSimon Schubert 	    p++;
1745796c8dcSSimon Schubert 
1755796c8dcSSimon Schubert 	  dirs[num_dirs++] = save_string (q, p - q);
1765796c8dcSSimon Schubert 	  if (dirs[num_dirs - 1] == NULL)
1775796c8dcSSimon Schubert 	    {
1785796c8dcSSimon Schubert 	      dirs[num_dirs] = NULL;
1795796c8dcSSimon Schubert 	      free_split_directories (dirs);
1805796c8dcSSimon Schubert 	      return NULL;
1815796c8dcSSimon Schubert 	    }
1825796c8dcSSimon Schubert 	  q = p;
1835796c8dcSSimon Schubert 	}
1845796c8dcSSimon Schubert     }
1855796c8dcSSimon Schubert 
1865796c8dcSSimon Schubert   if (p - 1 - q > 0)
1875796c8dcSSimon Schubert     dirs[num_dirs++] = save_string (q, p - 1 - q);
1885796c8dcSSimon Schubert   dirs[num_dirs] = NULL;
1895796c8dcSSimon Schubert 
1905796c8dcSSimon Schubert   if (dirs[num_dirs - 1] == NULL)
1915796c8dcSSimon Schubert     {
1925796c8dcSSimon Schubert       free_split_directories (dirs);
1935796c8dcSSimon Schubert       return NULL;
1945796c8dcSSimon Schubert     }
1955796c8dcSSimon Schubert 
1965796c8dcSSimon Schubert   if (ptr_num_dirs)
1975796c8dcSSimon Schubert     *ptr_num_dirs = num_dirs;
1985796c8dcSSimon Schubert   return dirs;
1995796c8dcSSimon Schubert }
2005796c8dcSSimon Schubert 
2015796c8dcSSimon Schubert /* Release storage held by split directories.  */
2025796c8dcSSimon Schubert 
2035796c8dcSSimon Schubert static void
free_split_directories(char ** dirs)2045796c8dcSSimon Schubert free_split_directories (char **dirs)
2055796c8dcSSimon Schubert {
2065796c8dcSSimon Schubert   int i = 0;
2075796c8dcSSimon Schubert 
2085796c8dcSSimon Schubert   if (dirs != NULL)
2095796c8dcSSimon Schubert     {
2105796c8dcSSimon Schubert       while (dirs[i] != NULL)
2115796c8dcSSimon Schubert 	free (dirs[i++]);
2125796c8dcSSimon Schubert 
2135796c8dcSSimon Schubert       free ((char *) dirs);
2145796c8dcSSimon Schubert     }
2155796c8dcSSimon Schubert }
2165796c8dcSSimon Schubert 
2175796c8dcSSimon Schubert /* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
2185796c8dcSSimon Schubert    to PREFIX starting with the directory portion of PROGNAME and a relative
2195796c8dcSSimon Schubert    pathname of the difference between BIN_PREFIX and PREFIX.
2205796c8dcSSimon Schubert 
2215796c8dcSSimon Schubert    For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
2225796c8dcSSimon Schubert    /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
2235796c8dcSSimon Schubert    function will return /red/green/blue/../../omega/.
2245796c8dcSSimon Schubert 
2255796c8dcSSimon Schubert    If no relative prefix can be found, return NULL.  */
2265796c8dcSSimon Schubert 
2275796c8dcSSimon Schubert static char *
make_relative_prefix_1(const char * progname,const char * bin_prefix,const char * prefix,const int resolve_links)2285796c8dcSSimon Schubert make_relative_prefix_1 (const char *progname, const char *bin_prefix,
2295796c8dcSSimon Schubert 			const char *prefix, const int resolve_links)
2305796c8dcSSimon Schubert {
2315796c8dcSSimon Schubert   char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
2325796c8dcSSimon Schubert   int prog_num, bin_num, prefix_num;
2335796c8dcSSimon Schubert   int i, n, common;
2345796c8dcSSimon Schubert   int needed_len;
2355796c8dcSSimon Schubert   char *ret = NULL, *ptr, *full_progname;
2365796c8dcSSimon Schubert 
2375796c8dcSSimon Schubert   if (progname == NULL || bin_prefix == NULL || prefix == NULL)
2385796c8dcSSimon Schubert     return NULL;
2395796c8dcSSimon Schubert 
2405796c8dcSSimon Schubert   /* If there is no full pathname, try to find the program by checking in each
2415796c8dcSSimon Schubert      of the directories specified in the PATH environment variable.  */
2425796c8dcSSimon Schubert   if (lbasename (progname) == progname)
2435796c8dcSSimon Schubert     {
2445796c8dcSSimon Schubert       char *temp;
2455796c8dcSSimon Schubert 
2465796c8dcSSimon Schubert       temp = getenv ("PATH");
2475796c8dcSSimon Schubert       if (temp)
2485796c8dcSSimon Schubert 	{
2495796c8dcSSimon Schubert 	  char *startp, *endp, *nstore;
2505796c8dcSSimon Schubert 	  size_t prefixlen = strlen (temp) + 1;
251*ef5ccd6cSJohn Marino 	  size_t len;
2525796c8dcSSimon Schubert 	  if (prefixlen < 2)
2535796c8dcSSimon Schubert 	    prefixlen = 2;
2545796c8dcSSimon Schubert 
255*ef5ccd6cSJohn Marino 	  len = prefixlen + strlen (progname) + 1;
256*ef5ccd6cSJohn Marino #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
257*ef5ccd6cSJohn Marino 	  len += strlen (HOST_EXECUTABLE_SUFFIX);
258*ef5ccd6cSJohn Marino #endif
259*ef5ccd6cSJohn Marino 	  nstore = (char *) alloca (len);
2605796c8dcSSimon Schubert 
2615796c8dcSSimon Schubert 	  startp = endp = temp;
2625796c8dcSSimon Schubert 	  while (1)
2635796c8dcSSimon Schubert 	    {
2645796c8dcSSimon Schubert 	      if (*endp == PATH_SEPARATOR || *endp == 0)
2655796c8dcSSimon Schubert 		{
2665796c8dcSSimon Schubert 		  if (endp == startp)
2675796c8dcSSimon Schubert 		    {
2685796c8dcSSimon Schubert 		      nstore[0] = '.';
2695796c8dcSSimon Schubert 		      nstore[1] = DIR_SEPARATOR;
2705796c8dcSSimon Schubert 		      nstore[2] = '\0';
2715796c8dcSSimon Schubert 		    }
2725796c8dcSSimon Schubert 		  else
2735796c8dcSSimon Schubert 		    {
274*ef5ccd6cSJohn Marino 		      memcpy (nstore, startp, endp - startp);
2755796c8dcSSimon Schubert 		      if (! IS_DIR_SEPARATOR (endp[-1]))
2765796c8dcSSimon Schubert 			{
2775796c8dcSSimon Schubert 			  nstore[endp - startp] = DIR_SEPARATOR;
2785796c8dcSSimon Schubert 			  nstore[endp - startp + 1] = 0;
2795796c8dcSSimon Schubert 			}
2805796c8dcSSimon Schubert 		      else
2815796c8dcSSimon Schubert 			nstore[endp - startp] = 0;
2825796c8dcSSimon Schubert 		    }
2835796c8dcSSimon Schubert 		  strcat (nstore, progname);
2845796c8dcSSimon Schubert 		  if (! access (nstore, X_OK)
2855796c8dcSSimon Schubert #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
2865796c8dcSSimon Schubert                       || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
2875796c8dcSSimon Schubert #endif
2885796c8dcSSimon Schubert 		      )
2895796c8dcSSimon Schubert 		    {
290*ef5ccd6cSJohn Marino #if defined (HAVE_SYS_STAT_H) && defined (S_ISREG)
291*ef5ccd6cSJohn Marino 		      struct stat st;
292*ef5ccd6cSJohn Marino 		      if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode))
293*ef5ccd6cSJohn Marino #endif
294*ef5ccd6cSJohn Marino 			{
2955796c8dcSSimon Schubert 			  progname = nstore;
2965796c8dcSSimon Schubert 			  break;
2975796c8dcSSimon Schubert 			}
298*ef5ccd6cSJohn Marino 		    }
2995796c8dcSSimon Schubert 
3005796c8dcSSimon Schubert 		  if (*endp == 0)
3015796c8dcSSimon Schubert 		    break;
3025796c8dcSSimon Schubert 		  endp = startp = endp + 1;
3035796c8dcSSimon Schubert 		}
3045796c8dcSSimon Schubert 	      else
3055796c8dcSSimon Schubert 		endp++;
3065796c8dcSSimon Schubert 	    }
3075796c8dcSSimon Schubert 	}
3085796c8dcSSimon Schubert     }
3095796c8dcSSimon Schubert 
3105796c8dcSSimon Schubert   if (resolve_links)
3115796c8dcSSimon Schubert     full_progname = lrealpath (progname);
3125796c8dcSSimon Schubert   else
3135796c8dcSSimon Schubert     full_progname = strdup (progname);
3145796c8dcSSimon Schubert   if (full_progname == NULL)
3155796c8dcSSimon Schubert     return NULL;
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert   prog_dirs = split_directories (full_progname, &prog_num);
3185796c8dcSSimon Schubert   free (full_progname);
3195796c8dcSSimon Schubert   if (prog_dirs == NULL)
3205796c8dcSSimon Schubert     return NULL;
3215796c8dcSSimon Schubert 
3225796c8dcSSimon Schubert   bin_dirs = split_directories (bin_prefix, &bin_num);
3235796c8dcSSimon Schubert   if (bin_dirs == NULL)
3245796c8dcSSimon Schubert     goto bailout;
3255796c8dcSSimon Schubert 
3265796c8dcSSimon Schubert   /* Remove the program name from comparison of directory names.  */
3275796c8dcSSimon Schubert   prog_num--;
3285796c8dcSSimon Schubert 
3295796c8dcSSimon Schubert   /* If we are still installed in the standard location, we don't need to
3305796c8dcSSimon Schubert      specify relative directories.  Also, if argv[0] still doesn't contain
3315796c8dcSSimon Schubert      any directory specifiers after the search above, then there is not much
3325796c8dcSSimon Schubert      we can do.  */
3335796c8dcSSimon Schubert   if (prog_num == bin_num)
3345796c8dcSSimon Schubert     {
3355796c8dcSSimon Schubert       for (i = 0; i < bin_num; i++)
3365796c8dcSSimon Schubert 	{
3375796c8dcSSimon Schubert 	  if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
3385796c8dcSSimon Schubert 	    break;
3395796c8dcSSimon Schubert 	}
3405796c8dcSSimon Schubert 
3415796c8dcSSimon Schubert       if (prog_num <= 0 || i == bin_num)
3425796c8dcSSimon Schubert 	goto bailout;
3435796c8dcSSimon Schubert     }
3445796c8dcSSimon Schubert 
3455796c8dcSSimon Schubert   prefix_dirs = split_directories (prefix, &prefix_num);
3465796c8dcSSimon Schubert   if (prefix_dirs == NULL)
3475796c8dcSSimon Schubert     goto bailout;
3485796c8dcSSimon Schubert 
3495796c8dcSSimon Schubert   /* Find how many directories are in common between bin_prefix & prefix.  */
3505796c8dcSSimon Schubert   n = (prefix_num < bin_num) ? prefix_num : bin_num;
3515796c8dcSSimon Schubert   for (common = 0; common < n; common++)
3525796c8dcSSimon Schubert     {
3535796c8dcSSimon Schubert       if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
3545796c8dcSSimon Schubert 	break;
3555796c8dcSSimon Schubert     }
3565796c8dcSSimon Schubert 
3575796c8dcSSimon Schubert   /* If there are no common directories, there can be no relative prefix.  */
3585796c8dcSSimon Schubert   if (common == 0)
3595796c8dcSSimon Schubert     goto bailout;
3605796c8dcSSimon Schubert 
3615796c8dcSSimon Schubert   /* Two passes: first figure out the size of the result string, and
3625796c8dcSSimon Schubert      then construct it.  */
3635796c8dcSSimon Schubert   needed_len = 0;
3645796c8dcSSimon Schubert   for (i = 0; i < prog_num; i++)
3655796c8dcSSimon Schubert     needed_len += strlen (prog_dirs[i]);
3665796c8dcSSimon Schubert   needed_len += sizeof (DIR_UP) * (bin_num - common);
3675796c8dcSSimon Schubert   for (i = common; i < prefix_num; i++)
3685796c8dcSSimon Schubert     needed_len += strlen (prefix_dirs[i]);
3695796c8dcSSimon Schubert   needed_len += 1; /* Trailing NUL.  */
3705796c8dcSSimon Schubert 
3715796c8dcSSimon Schubert   ret = (char *) malloc (needed_len);
3725796c8dcSSimon Schubert   if (ret == NULL)
3735796c8dcSSimon Schubert     goto bailout;
3745796c8dcSSimon Schubert 
3755796c8dcSSimon Schubert   /* Build up the pathnames in argv[0].  */
3765796c8dcSSimon Schubert   *ret = '\0';
3775796c8dcSSimon Schubert   for (i = 0; i < prog_num; i++)
3785796c8dcSSimon Schubert     strcat (ret, prog_dirs[i]);
3795796c8dcSSimon Schubert 
3805796c8dcSSimon Schubert   /* Now build up the ..'s.  */
3815796c8dcSSimon Schubert   ptr = ret + strlen(ret);
3825796c8dcSSimon Schubert   for (i = common; i < bin_num; i++)
3835796c8dcSSimon Schubert     {
3845796c8dcSSimon Schubert       strcpy (ptr, DIR_UP);
3855796c8dcSSimon Schubert       ptr += sizeof (DIR_UP) - 1;
3865796c8dcSSimon Schubert       *(ptr++) = DIR_SEPARATOR;
3875796c8dcSSimon Schubert     }
3885796c8dcSSimon Schubert   *ptr = '\0';
3895796c8dcSSimon Schubert 
3905796c8dcSSimon Schubert   /* Put in directories to move over to prefix.  */
3915796c8dcSSimon Schubert   for (i = common; i < prefix_num; i++)
3925796c8dcSSimon Schubert     strcat (ret, prefix_dirs[i]);
3935796c8dcSSimon Schubert 
3945796c8dcSSimon Schubert  bailout:
3955796c8dcSSimon Schubert   free_split_directories (prog_dirs);
3965796c8dcSSimon Schubert   free_split_directories (bin_dirs);
3975796c8dcSSimon Schubert   free_split_directories (prefix_dirs);
3985796c8dcSSimon Schubert 
3995796c8dcSSimon Schubert   return ret;
4005796c8dcSSimon Schubert }
4015796c8dcSSimon Schubert 
4025796c8dcSSimon Schubert 
4035796c8dcSSimon Schubert /* Do the full job, including symlink resolution.
4045796c8dcSSimon Schubert    This path will find files installed in the same place as the
4055796c8dcSSimon Schubert    program even when a soft link has been made to the program
4065796c8dcSSimon Schubert    from somwhere else. */
4075796c8dcSSimon Schubert 
4085796c8dcSSimon Schubert char *
make_relative_prefix(const char * progname,const char * bin_prefix,const char * prefix)4095796c8dcSSimon Schubert make_relative_prefix (const char *progname, const char *bin_prefix,
4105796c8dcSSimon Schubert 		      const char *prefix)
4115796c8dcSSimon Schubert {
4125796c8dcSSimon Schubert   return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
4135796c8dcSSimon Schubert }
4145796c8dcSSimon Schubert 
4155796c8dcSSimon Schubert /* Make the relative pathname without attempting to resolve any links.
4165796c8dcSSimon Schubert    '..' etc may also be left in the pathname.
4175796c8dcSSimon Schubert    This will find the files the user meant the program to find if the
4185796c8dcSSimon Schubert    installation is patched together with soft links. */
4195796c8dcSSimon Schubert 
4205796c8dcSSimon Schubert char *
make_relative_prefix_ignore_links(const char * progname,const char * bin_prefix,const char * prefix)4215796c8dcSSimon Schubert make_relative_prefix_ignore_links (const char *progname,
4225796c8dcSSimon Schubert 				   const char *bin_prefix,
4235796c8dcSSimon Schubert 				   const char *prefix)
4245796c8dcSSimon Schubert {
4255796c8dcSSimon Schubert   return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
4265796c8dcSSimon Schubert }
4275796c8dcSSimon Schubert 
428