prefix.c revision 225736
113840Swosch/* Utility to update paths from internal to external forms. 213840Swosch Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 313840Swosch Free Software Foundation, Inc. 413840Swosch 513840SwoschThis file is part of GCC. 613840Swosch 713840SwoschGCC is free software; you can redistribute it and/or modify it under 813840Swoschthe terms of the GNU Library General Public License as published by 913840Swoschthe Free Software Foundation; either version 2 of the License, or (at 1013840Swoschyour option) any later version. 1113840Swosch 1213840SwoschGCC is distributed in the hope that it will be useful, 1313840Swoschbut WITHOUT ANY WARRANTY; without even the implied warranty of 1413840SwoschMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1513840SwoschLibrary General Public License for more details. 1613840Swosch 1713840SwoschYou should have received a copy of the GNU Library General Public 1813840SwoschLicense along with GCC; see the file COPYING. If not, write to the Free 1913840SwoschSoftware Foundation, Inc., 51 Franklin Street, Fifth Floor, 2013840SwoschBoston, MA 02110-1301, USA. */ 2113840Swosch 2213840Swosch/* This file contains routines to update a path, both to canonicalize 2313840Swosch the directory format and to handle any prefix translation. 2413840Swosch 2513840Swosch This file must be compiled with -DPREFIX= to specify the "prefix" 2613840Swosch value used by configure. If a filename does not begin with this 2713840Swosch prefix, it will not be affected other than by directory canonicalization. 2813840Swosch 2913840Swosch Each caller of 'update_path' may specify both a filename and 3013840Swosch a translation prefix and consist of the name of the package that contains 3113840Swosch the file ("@GCC", "@BINUTIL", "@GNU", etc). 3213840Swosch 3313840Swosch If the prefix is not specified, the filename will only undergo 3413840Swosch directory canonicalization. 3513840Swosch 3613840Swosch If it is specified, the string given by PREFIX will be replaced 3713840Swosch by the specified prefix (with a '@' in front unless the prefix begins 3813840Swosch with a '$') and further translation will be done as follows 3913840Swosch until none of the two conditions below are met: 4013840Swosch 4113840Swosch 1) If the filename begins with '@', the string between the '@' and 4213840Swosch the end of the name or the first '/' or directory separator will 4313840Swosch be considered a "key" and looked up as follows: 4413840Swosch 4513840Swosch -- If this is a Win32 OS, then the Registry will be examined for 4613840Swosch an entry of "key" in 4713840Swosch 4813840Swosch HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY> 4913840Swosch 5013840Swosch if found, that value will be used. <KEY> defaults to GCC version 5113840Swosch string, but can be overridden at configuration time. 5213840Swosch 5313840Swosch -- If not found (or not a Win32 OS), the environment variable 5413840Swosch key_ROOT (the value of "key" concatenated with the constant "_ROOT") 5513840Swosch is tried. If that fails, then PREFIX (see above) is used. 5613840Swosch 5713840Swosch 2) If the filename begins with a '$', the rest of the string up 5813840Swosch to the end or the first '/' or directory separator will be used 5913840Swosch as an environment variable, whose value will be returned. 6013840Swosch 6113840Swosch Once all this is done, any '/' will be converted to DIR_SEPARATOR, 6213840Swosch if they are different. 6313840Swosch 6413840Swosch NOTE: using resolve_keyed_path under Win32 requires linking with 6513840Swosch advapi32.dll. */ 6613840Swosch 6713840Swosch 6813840Swosch#include "config.h" 6913840Swosch#include "system.h" 7013840Swosch#include "coretypes.h" 7113840Swosch#include "tm.h" 7213840Swosch#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 7313840Swosch#include <windows.h> 7413840Swosch#endif 7513840Swosch#include "prefix.h" 7613840Swosch 7713840Swoschstatic const char *std_prefix = PREFIX; 7813840Swosch 7913840Swoschstatic const char *get_key_value (char *); 8013840Swoschstatic char *translate_name (char *); 8113840Swoschstatic char *save_string (const char *, int); 8213840Swoschstatic void tr (char *, int, int); 8313840Swosch 8413840Swosch#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 8513840Swoschstatic char *lookup_key (char *); 8613840Swoschstatic HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE; 8713840Swosch#endif 8813840Swosch 8913840Swosch/* Given KEY, as above, return its value. */ 9013840Swosch 9113840Swoschstatic const char * 9213840Swoschget_key_value (char *key) 9313840Swosch{ 9413840Swosch const char *prefix = 0; 95 char *temp = 0; 96 97#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 98 prefix = lookup_key (key); 99#endif 100 101 if (prefix == 0) 102 prefix = getenv (temp = concat (key, "_ROOT", NULL)); 103 104 if (prefix == 0) 105 prefix = std_prefix; 106 107 if (temp) 108 free (temp); 109 110 return prefix; 111} 112 113/* Return a copy of a string that has been placed in the heap. */ 114 115static char * 116save_string (const char *s, int len) 117{ 118 char *result = XNEWVEC (char, len + 1); 119 120 memcpy (result, s, len); 121 result[len] = 0; 122 return result; 123} 124 125#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 126 127#ifndef WIN32_REGISTRY_KEY 128# define WIN32_REGISTRY_KEY BASEVER 129#endif 130 131/* Look up "key" in the registry, as above. */ 132 133static char * 134lookup_key (char *key) 135{ 136 char *dst; 137 DWORD size; 138 DWORD type; 139 LONG res; 140 141 if (reg_key == (HKEY) INVALID_HANDLE_VALUE) 142 { 143 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, 144 KEY_READ, ®_key); 145 146 if (res == ERROR_SUCCESS) 147 res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0, 148 KEY_READ, ®_key); 149 150 if (res == ERROR_SUCCESS) 151 res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0, 152 KEY_READ, ®_key); 153 154 if (res != ERROR_SUCCESS) 155 { 156 reg_key = (HKEY) INVALID_HANDLE_VALUE; 157 return 0; 158 } 159 } 160 161 size = 32; 162 dst = xmalloc (size); 163 164 res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); 165 if (res == ERROR_MORE_DATA && type == REG_SZ) 166 { 167 dst = xrealloc (dst, size); 168 res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); 169 } 170 171 if (type != REG_SZ || res != ERROR_SUCCESS) 172 { 173 free (dst); 174 dst = 0; 175 } 176 177 return dst; 178} 179#endif 180 181/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the 182 translation rules above and return a newly malloc-ed name. 183 Otherwise, return the given name. */ 184 185static char * 186translate_name (char *name) 187{ 188 char code; 189 char *key, *old_name; 190 const char *prefix; 191 int keylen; 192 193 for (;;) 194 { 195 code = name[0]; 196 if (code != '@' && code != '$') 197 break; 198 199 for (keylen = 0; 200 (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1])); 201 keylen++) 202 ; 203 204 key = (char *) alloca (keylen + 1); 205 strncpy (key, &name[1], keylen); 206 key[keylen] = 0; 207 208 if (code == '@') 209 { 210 prefix = get_key_value (key); 211 if (prefix == 0) 212 prefix = std_prefix; 213 } 214 else 215 prefix = getenv (key); 216 217 if (prefix == 0) 218 prefix = PREFIX; 219 220 /* We used to strip trailing DIR_SEPARATORs here, but that can 221 sometimes yield a result with no separator when one was coded 222 and intended by the user, causing two path components to run 223 together. */ 224 225 old_name = name; 226 name = concat (prefix, &name[keylen + 1], NULL); 227 free (old_name); 228 } 229 230 return name; 231} 232 233/* In a NUL-terminated STRING, replace character C1 with C2 in-place. */ 234static void 235tr (char *string, int c1, int c2) 236{ 237 do 238 { 239 if (*string == c1) 240 *string = c2; 241 } 242 while (*string++); 243} 244 245/* Update PATH using KEY if PATH starts with PREFIX as a directory. 246 The returned string is always malloc-ed, and the caller is 247 responsible for freeing it. */ 248 249char * 250update_path (const char *path, const char *key) 251{ 252 char *result, *p; 253 const int len = strlen (std_prefix); 254 255 if (! strncmp (path, std_prefix, len) 256 && (IS_DIR_SEPARATOR(path[len]) 257 || path[len] == '\0') 258 && key != 0) 259 { 260 bool free_key = false; 261 262 if (key[0] != '$') 263 { 264 key = concat ("@", key, NULL); 265 free_key = true; 266 } 267 268 result = concat (key, &path[len], NULL); 269 if (free_key) 270 free ((char *) key); 271 result = translate_name (result); 272 } 273 else 274 result = xstrdup (path); 275 276#ifndef ALWAYS_STRIP_DOTDOT 277#define ALWAYS_STRIP_DOTDOT 0 278#endif 279 280 p = result; 281 while (1) 282 { 283 char *src, *dest; 284 285 p = strchr (p, '.'); 286 if (p == NULL) 287 break; 288 /* Look for `/../' */ 289 if (p[1] == '.' 290 && IS_DIR_SEPARATOR (p[2]) 291 && (p != result && IS_DIR_SEPARATOR (p[-1]))) 292 { 293 *p = 0; 294 if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0) 295 { 296 *p = '.'; 297 break; 298 } 299 else 300 { 301 /* We can't access the dir, so we won't be able to 302 access dir/.. either. Strip out `dir/../'. If `dir' 303 turns out to be `.', strip one more path component. */ 304 dest = p; 305 do 306 { 307 --dest; 308 while (dest != result && IS_DIR_SEPARATOR (*dest)) 309 --dest; 310 while (dest != result && !IS_DIR_SEPARATOR (dest[-1])) 311 --dest; 312 } 313 while (dest != result && *dest == '.'); 314 /* If we have something like `./..' or `/..', don't 315 strip anything more. */ 316 if (*dest == '.' || IS_DIR_SEPARATOR (*dest)) 317 { 318 *p = '.'; 319 break; 320 } 321 src = p + 3; 322 while (IS_DIR_SEPARATOR (*src)) 323 ++src; 324 p = dest; 325 while ((*dest++ = *src++) != 0) 326 ; 327 } 328 } 329 else 330 ++p; 331 } 332 333#ifdef UPDATE_PATH_HOST_CANONICALIZE 334 /* Perform host dependent canonicalization when needed. */ 335 UPDATE_PATH_HOST_CANONICALIZE (result); 336#endif 337 338#ifdef DIR_SEPARATOR_2 339 /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */ 340 if (DIR_SEPARATOR_2 != DIR_SEPARATOR) 341 tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR); 342#endif 343 344#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2) 345 if (DIR_SEPARATOR != '/') 346 tr (result, '/', DIR_SEPARATOR); 347#endif 348 349 return result; 350} 351 352/* Reset the standard prefix. */ 353void 354set_std_prefix (const char *prefix, int len) 355{ 356 std_prefix = save_string (prefix, len); 357} 358