19588ddcfSespie /* Relative (relocatable) prefix support.
29588ddcfSespie Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
39588ddcfSespie 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
49588ddcfSespie
59588ddcfSespie This file is part of libiberty.
69588ddcfSespie
79588ddcfSespie GCC is free software; you can redistribute it and/or modify it under
89588ddcfSespie the terms of the GNU General Public License as published by the Free
99588ddcfSespie Software Foundation; either version 2, or (at your option) any later
109588ddcfSespie version.
119588ddcfSespie
129588ddcfSespie GCC is distributed in the hope that it will be useful, but WITHOUT ANY
139588ddcfSespie WARRANTY; without even the implied warranty of MERCHANTABILITY or
149588ddcfSespie FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
159588ddcfSespie for more details.
169588ddcfSespie
179588ddcfSespie You should have received a copy of the GNU General Public License
189588ddcfSespie along with GCC; see the file COPYING. If not, write to the Free
19*20fce977Smiod Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20*20fce977Smiod 02110-1301, USA. */
219588ddcfSespie
229588ddcfSespie /*
239588ddcfSespie
249588ddcfSespie @deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix})
259588ddcfSespie
2632d62142Sespie Given three paths @var{progname}, @var{bin_prefix}, @var{prefix},
2732d62142Sespie return the path that is in the same position relative to
2832d62142Sespie @var{progname}'s directory as @var{prefix} is relative to
2932d62142Sespie @var{bin_prefix}. That is, a string starting with the directory
3032d62142Sespie portion of @var{progname}, followed by a relative pathname of the
3132d62142Sespie difference between @var{bin_prefix} and @var{prefix}.
329588ddcfSespie
3332d62142Sespie If @var{progname} does not contain any directory separators,
3432d62142Sespie @code{make_relative_prefix} will search @env{PATH} to find a program
3532d62142Sespie named @var{progname}. Also, if @var{progname} is a symbolic link,
3632d62142Sespie the symbolic link will be resolved.
379588ddcfSespie
3832d62142Sespie For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta},
3932d62142Sespie @var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is
4032d62142Sespie @code{/red/green/blue/gcc}, then this function will return
4132d62142Sespie @code{/red/green/blue/../../omega/}.
4232d62142Sespie
4332d62142Sespie The return value is normally allocated via @code{malloc}. If no
4432d62142Sespie relative prefix can be found, return @code{NULL}.
459588ddcfSespie
469588ddcfSespie @end deftypefn
479588ddcfSespie
489588ddcfSespie */
499588ddcfSespie
509588ddcfSespie #ifdef HAVE_CONFIG_H
519588ddcfSespie #include "config.h"
529588ddcfSespie #endif
539588ddcfSespie
549588ddcfSespie #ifdef HAVE_STDLIB_H
559588ddcfSespie #include <stdlib.h>
569588ddcfSespie #endif
579588ddcfSespie #ifdef HAVE_UNISTD_H
589588ddcfSespie #include <unistd.h>
599588ddcfSespie #endif
609588ddcfSespie
619588ddcfSespie #include <string.h>
629588ddcfSespie
639588ddcfSespie #include "ansidecl.h"
649588ddcfSespie #include "libiberty.h"
659588ddcfSespie
669588ddcfSespie #ifndef R_OK
679588ddcfSespie #define R_OK 4
689588ddcfSespie #define W_OK 2
699588ddcfSespie #define X_OK 1
709588ddcfSespie #endif
719588ddcfSespie
729588ddcfSespie #ifndef DIR_SEPARATOR
739588ddcfSespie # define DIR_SEPARATOR '/'
749588ddcfSespie #endif
759588ddcfSespie
769588ddcfSespie #if defined (_WIN32) || defined (__MSDOS__) \
779588ddcfSespie || defined (__DJGPP__) || defined (__OS2__)
789588ddcfSespie # define HAVE_DOS_BASED_FILE_SYSTEM
799588ddcfSespie # define HAVE_HOST_EXECUTABLE_SUFFIX
809588ddcfSespie # define HOST_EXECUTABLE_SUFFIX ".exe"
819588ddcfSespie # ifndef DIR_SEPARATOR_2
829588ddcfSespie # define DIR_SEPARATOR_2 '\\'
839588ddcfSespie # endif
849588ddcfSespie # define PATH_SEPARATOR ';'
859588ddcfSespie #else
869588ddcfSespie # define PATH_SEPARATOR ':'
879588ddcfSespie #endif
889588ddcfSespie
899588ddcfSespie #ifndef DIR_SEPARATOR_2
909588ddcfSespie # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
919588ddcfSespie #else
929588ddcfSespie # define IS_DIR_SEPARATOR(ch) \
939588ddcfSespie (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
949588ddcfSespie #endif
959588ddcfSespie
969588ddcfSespie #define DIR_UP ".."
979588ddcfSespie
98*20fce977Smiod static char *save_string (const char *, int);
99*20fce977Smiod static char **split_directories (const char *, int *);
100*20fce977Smiod static void free_split_directories (char **);
1019588ddcfSespie
1029588ddcfSespie static char *
save_string(const char * s,int len)103*20fce977Smiod save_string (const char *s, int len)
1049588ddcfSespie {
105*20fce977Smiod char *result = (char *) malloc (len + 1);
1069588ddcfSespie
1079588ddcfSespie memcpy (result, s, len);
1089588ddcfSespie result[len] = 0;
1099588ddcfSespie return result;
1109588ddcfSespie }
1119588ddcfSespie
1129588ddcfSespie /* Split a filename into component directories. */
1139588ddcfSespie
1149588ddcfSespie static char **
split_directories(const char * name,int * ptr_num_dirs)115*20fce977Smiod split_directories (const char *name, int *ptr_num_dirs)
1169588ddcfSespie {
1179588ddcfSespie int num_dirs = 0;
1189588ddcfSespie char **dirs;
1199588ddcfSespie const char *p, *q;
1209588ddcfSespie int ch;
1219588ddcfSespie
1229588ddcfSespie /* Count the number of directories. Special case MSDOS disk names as part
1239588ddcfSespie of the initial directory. */
1249588ddcfSespie p = name;
1259588ddcfSespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1269588ddcfSespie if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
1279588ddcfSespie {
1289588ddcfSespie p += 3;
1299588ddcfSespie num_dirs++;
1309588ddcfSespie }
1319588ddcfSespie #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
1329588ddcfSespie
1339588ddcfSespie while ((ch = *p++) != '\0')
1349588ddcfSespie {
1359588ddcfSespie if (IS_DIR_SEPARATOR (ch))
1369588ddcfSespie {
1379588ddcfSespie num_dirs++;
1389588ddcfSespie while (IS_DIR_SEPARATOR (*p))
1399588ddcfSespie p++;
1409588ddcfSespie }
1419588ddcfSespie }
1429588ddcfSespie
1439588ddcfSespie dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
1449588ddcfSespie if (dirs == NULL)
1459588ddcfSespie return NULL;
1469588ddcfSespie
1479588ddcfSespie /* Now copy the directory parts. */
1489588ddcfSespie num_dirs = 0;
1499588ddcfSespie p = name;
1509588ddcfSespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
1519588ddcfSespie if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
1529588ddcfSespie {
1539588ddcfSespie dirs[num_dirs++] = save_string (p, 3);
1549588ddcfSespie if (dirs[num_dirs - 1] == NULL)
1559588ddcfSespie {
1569588ddcfSespie free (dirs);
1579588ddcfSespie return NULL;
1589588ddcfSespie }
1599588ddcfSespie p += 3;
1609588ddcfSespie }
1619588ddcfSespie #endif /* HAVE_DOS_BASED_FILE_SYSTEM */
1629588ddcfSespie
1639588ddcfSespie q = p;
1649588ddcfSespie while ((ch = *p++) != '\0')
1659588ddcfSespie {
1669588ddcfSespie if (IS_DIR_SEPARATOR (ch))
1679588ddcfSespie {
1689588ddcfSespie while (IS_DIR_SEPARATOR (*p))
1699588ddcfSespie p++;
1709588ddcfSespie
1719588ddcfSespie dirs[num_dirs++] = save_string (q, p - q);
1729588ddcfSespie if (dirs[num_dirs - 1] == NULL)
1739588ddcfSespie {
1749588ddcfSespie dirs[num_dirs] = NULL;
1759588ddcfSespie free_split_directories (dirs);
1769588ddcfSespie return NULL;
1779588ddcfSespie }
1789588ddcfSespie q = p;
1799588ddcfSespie }
1809588ddcfSespie }
1819588ddcfSespie
1829588ddcfSespie if (p - 1 - q > 0)
1839588ddcfSespie dirs[num_dirs++] = save_string (q, p - 1 - q);
1849588ddcfSespie dirs[num_dirs] = NULL;
1859588ddcfSespie
1869588ddcfSespie if (dirs[num_dirs - 1] == NULL)
1879588ddcfSespie {
1889588ddcfSespie free_split_directories (dirs);
1899588ddcfSespie return NULL;
1909588ddcfSespie }
1919588ddcfSespie
1929588ddcfSespie if (ptr_num_dirs)
1939588ddcfSespie *ptr_num_dirs = num_dirs;
1949588ddcfSespie return dirs;
1959588ddcfSespie }
1969588ddcfSespie
1979588ddcfSespie /* Release storage held by split directories. */
1989588ddcfSespie
1999588ddcfSespie static void
free_split_directories(char ** dirs)200*20fce977Smiod free_split_directories (char **dirs)
2019588ddcfSespie {
2029588ddcfSespie int i = 0;
2039588ddcfSespie
2049588ddcfSespie while (dirs[i] != NULL)
2059588ddcfSespie free (dirs[i++]);
2069588ddcfSespie
2079588ddcfSespie free ((char *) dirs);
2089588ddcfSespie }
2099588ddcfSespie
2109588ddcfSespie /* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
2119588ddcfSespie to PREFIX starting with the directory portion of PROGNAME and a relative
2129588ddcfSespie pathname of the difference between BIN_PREFIX and PREFIX.
2139588ddcfSespie
2149588ddcfSespie For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
2159588ddcfSespie /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
2169588ddcfSespie function will return /red/green/blue/../../omega/.
2179588ddcfSespie
2189588ddcfSespie If no relative prefix can be found, return NULL. */
2199588ddcfSespie
2209588ddcfSespie char *
make_relative_prefix(const char * progname,const char * bin_prefix,const char * prefix)221*20fce977Smiod make_relative_prefix (const char *progname,
222*20fce977Smiod const char *bin_prefix, const char *prefix)
2239588ddcfSespie {
2249588ddcfSespie char **prog_dirs, **bin_dirs, **prefix_dirs;
2259588ddcfSespie int prog_num, bin_num, prefix_num;
2269588ddcfSespie int i, n, common;
2279588ddcfSespie int needed_len;
22832d62142Sespie char *ret, *ptr, *full_progname = NULL;
2299588ddcfSespie
2309588ddcfSespie if (progname == NULL || bin_prefix == NULL || prefix == NULL)
2319588ddcfSespie return NULL;
2329588ddcfSespie
2339588ddcfSespie /* If there is no full pathname, try to find the program by checking in each
2349588ddcfSespie of the directories specified in the PATH environment variable. */
23532d62142Sespie if (lbasename (progname) == progname)
2369588ddcfSespie {
2379588ddcfSespie char *temp;
2389588ddcfSespie
2399588ddcfSespie temp = getenv ("PATH");
2409588ddcfSespie if (temp)
2419588ddcfSespie {
2429588ddcfSespie char *startp, *endp, *nstore;
2439588ddcfSespie size_t prefixlen = strlen (temp) + 1;
2449588ddcfSespie if (prefixlen < 2)
2459588ddcfSespie prefixlen = 2;
2469588ddcfSespie
2479588ddcfSespie nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
2489588ddcfSespie
2499588ddcfSespie startp = endp = temp;
2509588ddcfSespie while (1)
2519588ddcfSespie {
2529588ddcfSespie if (*endp == PATH_SEPARATOR || *endp == 0)
2539588ddcfSespie {
2549588ddcfSespie if (endp == startp)
2559588ddcfSespie {
2569588ddcfSespie nstore[0] = '.';
2579588ddcfSespie nstore[1] = DIR_SEPARATOR;
2589588ddcfSespie nstore[2] = '\0';
2599588ddcfSespie }
2609588ddcfSespie else
2619588ddcfSespie {
2629588ddcfSespie strncpy (nstore, startp, endp - startp);
2639588ddcfSespie if (! IS_DIR_SEPARATOR (endp[-1]))
2649588ddcfSespie {
2659588ddcfSespie nstore[endp - startp] = DIR_SEPARATOR;
2669588ddcfSespie nstore[endp - startp + 1] = 0;
2679588ddcfSespie }
2689588ddcfSespie else
2699588ddcfSespie nstore[endp - startp] = 0;
2709588ddcfSespie }
2719588ddcfSespie strcat (nstore, progname);
2729588ddcfSespie if (! access (nstore, X_OK)
2739588ddcfSespie #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
2749588ddcfSespie || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
2759588ddcfSespie #endif
2769588ddcfSespie )
2779588ddcfSespie {
2789588ddcfSespie progname = nstore;
2799588ddcfSespie break;
2809588ddcfSespie }
2819588ddcfSespie
2829588ddcfSespie if (*endp == 0)
2839588ddcfSespie break;
2849588ddcfSespie endp = startp = endp + 1;
2859588ddcfSespie }
2869588ddcfSespie else
2879588ddcfSespie endp++;
2889588ddcfSespie }
2899588ddcfSespie }
2909588ddcfSespie }
2919588ddcfSespie
29232d62142Sespie full_progname = lrealpath (progname);
29332d62142Sespie if (full_progname == NULL)
29432d62142Sespie return NULL;
29532d62142Sespie
29632d62142Sespie prog_dirs = split_directories (full_progname, &prog_num);
29732d62142Sespie bin_dirs = split_directories (bin_prefix, &bin_num);
29832d62142Sespie free (full_progname);
29932d62142Sespie if (bin_dirs == NULL || prog_dirs == NULL)
30032d62142Sespie return NULL;
30132d62142Sespie
3029588ddcfSespie /* Remove the program name from comparison of directory names. */
3039588ddcfSespie prog_num--;
3049588ddcfSespie
3059588ddcfSespie /* If we are still installed in the standard location, we don't need to
3069588ddcfSespie specify relative directories. Also, if argv[0] still doesn't contain
3079588ddcfSespie any directory specifiers after the search above, then there is not much
3089588ddcfSespie we can do. */
3099588ddcfSespie if (prog_num == bin_num)
3109588ddcfSespie {
3119588ddcfSespie for (i = 0; i < bin_num; i++)
3129588ddcfSespie {
3139588ddcfSespie if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
3149588ddcfSespie break;
3159588ddcfSespie }
3169588ddcfSespie
3179588ddcfSespie if (prog_num <= 0 || i == bin_num)
3189588ddcfSespie {
3199588ddcfSespie free_split_directories (prog_dirs);
3209588ddcfSespie free_split_directories (bin_dirs);
3219588ddcfSespie prog_dirs = bin_dirs = (char **) 0;
3229588ddcfSespie return NULL;
3239588ddcfSespie }
3249588ddcfSespie }
3259588ddcfSespie
3269588ddcfSespie prefix_dirs = split_directories (prefix, &prefix_num);
3279588ddcfSespie if (prefix_dirs == NULL)
3289588ddcfSespie {
3299588ddcfSespie free_split_directories (prog_dirs);
3309588ddcfSespie free_split_directories (bin_dirs);
3319588ddcfSespie return NULL;
3329588ddcfSespie }
3339588ddcfSespie
3349588ddcfSespie /* Find how many directories are in common between bin_prefix & prefix. */
3359588ddcfSespie n = (prefix_num < bin_num) ? prefix_num : bin_num;
3369588ddcfSespie for (common = 0; common < n; common++)
3379588ddcfSespie {
3389588ddcfSespie if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
3399588ddcfSespie break;
3409588ddcfSespie }
3419588ddcfSespie
3429588ddcfSespie /* If there are no common directories, there can be no relative prefix. */
3439588ddcfSespie if (common == 0)
3449588ddcfSespie {
3459588ddcfSespie free_split_directories (prog_dirs);
3469588ddcfSespie free_split_directories (bin_dirs);
3479588ddcfSespie free_split_directories (prefix_dirs);
3489588ddcfSespie return NULL;
3499588ddcfSespie }
3509588ddcfSespie
3519588ddcfSespie /* Two passes: first figure out the size of the result string, and
3529588ddcfSespie then construct it. */
3539588ddcfSespie needed_len = 0;
3549588ddcfSespie for (i = 0; i < prog_num; i++)
3559588ddcfSespie needed_len += strlen (prog_dirs[i]);
3569588ddcfSespie needed_len += sizeof (DIR_UP) * (bin_num - common);
3579588ddcfSespie for (i = common; i < prefix_num; i++)
3589588ddcfSespie needed_len += strlen (prefix_dirs[i]);
3599588ddcfSespie needed_len += 1; /* Trailing NUL. */
3609588ddcfSespie
3619588ddcfSespie ret = (char *) malloc (needed_len);
3629588ddcfSespie if (ret == NULL)
3639588ddcfSespie return NULL;
3649588ddcfSespie
3659588ddcfSespie /* Build up the pathnames in argv[0]. */
3669588ddcfSespie *ret = '\0';
3679588ddcfSespie for (i = 0; i < prog_num; i++)
3689588ddcfSespie strcat (ret, prog_dirs[i]);
3699588ddcfSespie
3709588ddcfSespie /* Now build up the ..'s. */
3719588ddcfSespie ptr = ret + strlen(ret);
3729588ddcfSespie for (i = common; i < bin_num; i++)
3739588ddcfSespie {
3749588ddcfSespie strcpy (ptr, DIR_UP);
3759588ddcfSespie ptr += sizeof (DIR_UP) - 1;
3769588ddcfSespie *(ptr++) = DIR_SEPARATOR;
3779588ddcfSespie }
3789588ddcfSespie *ptr = '\0';
3799588ddcfSespie
3809588ddcfSespie /* Put in directories to move over to prefix. */
3819588ddcfSespie for (i = common; i < prefix_num; i++)
3829588ddcfSespie strcat (ret, prefix_dirs[i]);
3839588ddcfSespie
3849588ddcfSespie free_split_directories (prog_dirs);
3859588ddcfSespie free_split_directories (bin_dirs);
3869588ddcfSespie free_split_directories (prefix_dirs);
3879588ddcfSespie
3889588ddcfSespie return ret;
3899588ddcfSespie }
390