1169695Skan/* Relative (relocatable) prefix support. 2169695Skan Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3169695Skan 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 4169695Skan 5169695SkanThis file is part of libiberty. 6169695Skan 7169695SkanGCC is free software; you can redistribute it and/or modify it under 8169695Skanthe terms of the GNU General Public License as published by the Free 9169695SkanSoftware Foundation; either version 2, or (at your option) any later 10169695Skanversion. 11169695Skan 12169695SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13169695SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 14169695SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15169695Skanfor more details. 16169695Skan 17169695SkanYou should have received a copy of the GNU General Public License 18169695Skanalong with GCC; see the file COPYING. If not, write to the Free 19169695SkanSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 20169695Skan02110-1301, USA. */ 21169695Skan 22169695Skan/* 23169695Skan 24169695Skan@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) 25169695Skan 26169695SkanGiven three paths @var{progname}, @var{bin_prefix}, @var{prefix}, 27169695Skanreturn the path that is in the same position relative to 28169695Skan@var{progname}'s directory as @var{prefix} is relative to 29169695Skan@var{bin_prefix}. That is, a string starting with the directory 30169695Skanportion of @var{progname}, followed by a relative pathname of the 31169695Skandifference between @var{bin_prefix} and @var{prefix}. 32169695Skan 33169695SkanIf @var{progname} does not contain any directory separators, 34169695Skan@code{make_relative_prefix} will search @env{PATH} to find a program 35169695Skannamed @var{progname}. Also, if @var{progname} is a symbolic link, 36169695Skanthe symbolic link will be resolved. 37169695Skan 38169695SkanFor example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, 39169695Skan@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is 40169695Skan@code{/red/green/blue/gcc}, then this function will return 41169695Skan@code{/red/green/blue/../../omega/}. 42169695Skan 43169695SkanThe return value is normally allocated via @code{malloc}. If no 44169695Skanrelative prefix can be found, return @code{NULL}. 45169695Skan 46169695Skan@end deftypefn 47169695Skan 48169695Skan*/ 49169695Skan 50169695Skan#ifdef HAVE_CONFIG_H 51169695Skan#include "config.h" 52169695Skan#endif 53169695Skan 54169695Skan#ifdef HAVE_STDLIB_H 55169695Skan#include <stdlib.h> 56169695Skan#endif 57169695Skan#ifdef HAVE_UNISTD_H 58169695Skan#include <unistd.h> 59169695Skan#endif 60169695Skan 61169695Skan#include <string.h> 62169695Skan 63169695Skan#include "ansidecl.h" 64169695Skan#include "libiberty.h" 65169695Skan 66169695Skan#ifndef R_OK 67169695Skan#define R_OK 4 68169695Skan#define W_OK 2 69169695Skan#define X_OK 1 70169695Skan#endif 71169695Skan 72169695Skan#ifndef DIR_SEPARATOR 73169695Skan# define DIR_SEPARATOR '/' 74169695Skan#endif 75169695Skan 76169695Skan#if defined (_WIN32) || defined (__MSDOS__) \ 77169695Skan || defined (__DJGPP__) || defined (__OS2__) 78169695Skan# define HAVE_DOS_BASED_FILE_SYSTEM 79169695Skan# define HAVE_HOST_EXECUTABLE_SUFFIX 80169695Skan# define HOST_EXECUTABLE_SUFFIX ".exe" 81169695Skan# ifndef DIR_SEPARATOR_2 82169695Skan# define DIR_SEPARATOR_2 '\\' 83169695Skan# endif 84169695Skan# define PATH_SEPARATOR ';' 85169695Skan#else 86169695Skan# define PATH_SEPARATOR ':' 87169695Skan#endif 88169695Skan 89169695Skan#ifndef DIR_SEPARATOR_2 90169695Skan# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) 91169695Skan#else 92169695Skan# define IS_DIR_SEPARATOR(ch) \ 93169695Skan (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) 94169695Skan#endif 95169695Skan 96169695Skan#define DIR_UP ".." 97169695Skan 98169695Skanstatic char *save_string (const char *, int); 99169695Skanstatic char **split_directories (const char *, int *); 100169695Skanstatic void free_split_directories (char **); 101169695Skan 102169695Skanstatic char * 103169695Skansave_string (const char *s, int len) 104169695Skan{ 105169695Skan char *result = (char *) malloc (len + 1); 106169695Skan 107169695Skan memcpy (result, s, len); 108169695Skan result[len] = 0; 109169695Skan return result; 110169695Skan} 111169695Skan 112169695Skan/* Split a filename into component directories. */ 113169695Skan 114169695Skanstatic char ** 115169695Skansplit_directories (const char *name, int *ptr_num_dirs) 116169695Skan{ 117169695Skan int num_dirs = 0; 118169695Skan char **dirs; 119169695Skan const char *p, *q; 120169695Skan int ch; 121169695Skan 122169695Skan /* Count the number of directories. Special case MSDOS disk names as part 123169695Skan of the initial directory. */ 124169695Skan p = name; 125169695Skan#ifdef HAVE_DOS_BASED_FILE_SYSTEM 126169695Skan if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) 127169695Skan { 128169695Skan p += 3; 129169695Skan num_dirs++; 130169695Skan } 131169695Skan#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ 132169695Skan 133169695Skan while ((ch = *p++) != '\0') 134169695Skan { 135169695Skan if (IS_DIR_SEPARATOR (ch)) 136169695Skan { 137169695Skan num_dirs++; 138169695Skan while (IS_DIR_SEPARATOR (*p)) 139169695Skan p++; 140169695Skan } 141169695Skan } 142169695Skan 143169695Skan dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); 144169695Skan if (dirs == NULL) 145169695Skan return NULL; 146169695Skan 147169695Skan /* Now copy the directory parts. */ 148169695Skan num_dirs = 0; 149169695Skan p = name; 150169695Skan#ifdef HAVE_DOS_BASED_FILE_SYSTEM 151169695Skan if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) 152169695Skan { 153169695Skan dirs[num_dirs++] = save_string (p, 3); 154169695Skan if (dirs[num_dirs - 1] == NULL) 155169695Skan { 156169695Skan free (dirs); 157169695Skan return NULL; 158169695Skan } 159169695Skan p += 3; 160169695Skan } 161169695Skan#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ 162169695Skan 163169695Skan q = p; 164169695Skan while ((ch = *p++) != '\0') 165169695Skan { 166169695Skan if (IS_DIR_SEPARATOR (ch)) 167169695Skan { 168169695Skan while (IS_DIR_SEPARATOR (*p)) 169169695Skan p++; 170169695Skan 171169695Skan dirs[num_dirs++] = save_string (q, p - q); 172169695Skan if (dirs[num_dirs - 1] == NULL) 173169695Skan { 174169695Skan dirs[num_dirs] = NULL; 175169695Skan free_split_directories (dirs); 176169695Skan return NULL; 177169695Skan } 178169695Skan q = p; 179169695Skan } 180169695Skan } 181169695Skan 182169695Skan if (p - 1 - q > 0) 183169695Skan dirs[num_dirs++] = save_string (q, p - 1 - q); 184169695Skan dirs[num_dirs] = NULL; 185169695Skan 186169695Skan if (dirs[num_dirs - 1] == NULL) 187169695Skan { 188169695Skan free_split_directories (dirs); 189169695Skan return NULL; 190169695Skan } 191169695Skan 192169695Skan if (ptr_num_dirs) 193169695Skan *ptr_num_dirs = num_dirs; 194169695Skan return dirs; 195169695Skan} 196169695Skan 197169695Skan/* Release storage held by split directories. */ 198169695Skan 199169695Skanstatic void 200169695Skanfree_split_directories (char **dirs) 201169695Skan{ 202169695Skan int i = 0; 203169695Skan 204169695Skan while (dirs[i] != NULL) 205169695Skan free (dirs[i++]); 206169695Skan 207169695Skan free ((char *) dirs); 208169695Skan} 209169695Skan 210169695Skan/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets 211169695Skan to PREFIX starting with the directory portion of PROGNAME and a relative 212169695Skan pathname of the difference between BIN_PREFIX and PREFIX. 213169695Skan 214169695Skan For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is 215169695Skan /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this 216169695Skan function will return /red/green/blue/../../omega/. 217169695Skan 218169695Skan If no relative prefix can be found, return NULL. */ 219169695Skan 220169695Skanchar * 221169695Skanmake_relative_prefix (const char *progname, 222169695Skan const char *bin_prefix, const char *prefix) 223169695Skan{ 224169695Skan char **prog_dirs, **bin_dirs, **prefix_dirs; 225169695Skan int prog_num, bin_num, prefix_num; 226169695Skan int i, n, common; 227169695Skan int needed_len; 228169695Skan char *ret, *ptr, *full_progname = NULL; 229169695Skan 230169695Skan if (progname == NULL || bin_prefix == NULL || prefix == NULL) 231169695Skan return NULL; 232169695Skan 233169695Skan /* If there is no full pathname, try to find the program by checking in each 234169695Skan of the directories specified in the PATH environment variable. */ 235169695Skan if (lbasename (progname) == progname) 236169695Skan { 237169695Skan char *temp; 238169695Skan 239169695Skan temp = getenv ("PATH"); 240169695Skan if (temp) 241169695Skan { 242169695Skan char *startp, *endp, *nstore; 243169695Skan size_t prefixlen = strlen (temp) + 1; 244169695Skan if (prefixlen < 2) 245169695Skan prefixlen = 2; 246169695Skan 247169695Skan nstore = (char *) alloca (prefixlen + strlen (progname) + 1); 248169695Skan 249169695Skan startp = endp = temp; 250169695Skan while (1) 251169695Skan { 252169695Skan if (*endp == PATH_SEPARATOR || *endp == 0) 253169695Skan { 254169695Skan if (endp == startp) 255169695Skan { 256169695Skan nstore[0] = '.'; 257169695Skan nstore[1] = DIR_SEPARATOR; 258169695Skan nstore[2] = '\0'; 259169695Skan } 260169695Skan else 261169695Skan { 262169695Skan strncpy (nstore, startp, endp - startp); 263169695Skan if (! IS_DIR_SEPARATOR (endp[-1])) 264169695Skan { 265169695Skan nstore[endp - startp] = DIR_SEPARATOR; 266169695Skan nstore[endp - startp + 1] = 0; 267169695Skan } 268169695Skan else 269169695Skan nstore[endp - startp] = 0; 270169695Skan } 271169695Skan strcat (nstore, progname); 272169695Skan if (! access (nstore, X_OK) 273169695Skan#ifdef HAVE_HOST_EXECUTABLE_SUFFIX 274169695Skan || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) 275169695Skan#endif 276169695Skan ) 277169695Skan { 278169695Skan progname = nstore; 279169695Skan break; 280169695Skan } 281169695Skan 282169695Skan if (*endp == 0) 283169695Skan break; 284169695Skan endp = startp = endp + 1; 285169695Skan } 286169695Skan else 287169695Skan endp++; 288169695Skan } 289169695Skan } 290169695Skan } 291169695Skan 292169695Skan full_progname = lrealpath (progname); 293169695Skan if (full_progname == NULL) 294169695Skan return NULL; 295169695Skan 296169695Skan prog_dirs = split_directories (full_progname, &prog_num); 297169695Skan bin_dirs = split_directories (bin_prefix, &bin_num); 298169695Skan free (full_progname); 299169695Skan if (bin_dirs == NULL || prog_dirs == NULL) 300169695Skan return NULL; 301169695Skan 302169695Skan /* Remove the program name from comparison of directory names. */ 303169695Skan prog_num--; 304169695Skan 305169695Skan /* If we are still installed in the standard location, we don't need to 306169695Skan specify relative directories. Also, if argv[0] still doesn't contain 307169695Skan any directory specifiers after the search above, then there is not much 308169695Skan we can do. */ 309169695Skan if (prog_num == bin_num) 310169695Skan { 311169695Skan for (i = 0; i < bin_num; i++) 312169695Skan { 313169695Skan if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) 314169695Skan break; 315169695Skan } 316169695Skan 317169695Skan if (prog_num <= 0 || i == bin_num) 318169695Skan { 319169695Skan free_split_directories (prog_dirs); 320169695Skan free_split_directories (bin_dirs); 321169695Skan prog_dirs = bin_dirs = (char **) 0; 322169695Skan return NULL; 323169695Skan } 324169695Skan } 325169695Skan 326169695Skan prefix_dirs = split_directories (prefix, &prefix_num); 327169695Skan if (prefix_dirs == NULL) 328169695Skan { 329169695Skan free_split_directories (prog_dirs); 330169695Skan free_split_directories (bin_dirs); 331169695Skan return NULL; 332169695Skan } 333169695Skan 334169695Skan /* Find how many directories are in common between bin_prefix & prefix. */ 335169695Skan n = (prefix_num < bin_num) ? prefix_num : bin_num; 336169695Skan for (common = 0; common < n; common++) 337169695Skan { 338169695Skan if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) 339169695Skan break; 340169695Skan } 341169695Skan 342169695Skan /* If there are no common directories, there can be no relative prefix. */ 343169695Skan if (common == 0) 344169695Skan { 345169695Skan free_split_directories (prog_dirs); 346169695Skan free_split_directories (bin_dirs); 347169695Skan free_split_directories (prefix_dirs); 348169695Skan return NULL; 349169695Skan } 350169695Skan 351169695Skan /* Two passes: first figure out the size of the result string, and 352169695Skan then construct it. */ 353169695Skan needed_len = 0; 354169695Skan for (i = 0; i < prog_num; i++) 355169695Skan needed_len += strlen (prog_dirs[i]); 356169695Skan needed_len += sizeof (DIR_UP) * (bin_num - common); 357169695Skan for (i = common; i < prefix_num; i++) 358169695Skan needed_len += strlen (prefix_dirs[i]); 359169695Skan needed_len += 1; /* Trailing NUL. */ 360169695Skan 361169695Skan ret = (char *) malloc (needed_len); 362169695Skan if (ret == NULL) 363169695Skan return NULL; 364169695Skan 365169695Skan /* Build up the pathnames in argv[0]. */ 366169695Skan *ret = '\0'; 367169695Skan for (i = 0; i < prog_num; i++) 368169695Skan strcat (ret, prog_dirs[i]); 369169695Skan 370169695Skan /* Now build up the ..'s. */ 371169695Skan ptr = ret + strlen(ret); 372169695Skan for (i = common; i < bin_num; i++) 373169695Skan { 374169695Skan strcpy (ptr, DIR_UP); 375169695Skan ptr += sizeof (DIR_UP) - 1; 376169695Skan *(ptr++) = DIR_SEPARATOR; 377169695Skan } 378169695Skan *ptr = '\0'; 379169695Skan 380169695Skan /* Put in directories to move over to prefix. */ 381169695Skan for (i = common; i < prefix_num; i++) 382169695Skan strcat (ret, prefix_dirs[i]); 383169695Skan 384169695Skan free_split_directories (prog_dirs); 385169695Skan free_split_directories (bin_dirs); 386169695Skan free_split_directories (prefix_dirs); 387169695Skan 388169695Skan return ret; 389169695Skan} 390