150397Sobrien/* Utility to update paths from internal to external forms. 2169689Skan Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 3117395Skan Free Software Foundation, Inc. 450397Sobrien 590075SobrienThis file is part of GCC. 650397Sobrien 790075SobrienGCC is free software; you can redistribute it and/or modify it under 890075Sobrienthe terms of the GNU Library General Public License as published by 990075Sobrienthe Free Software Foundation; either version 2 of the License, or (at 1090075Sobrienyour option) any later version. 1150397Sobrien 1250397SobrienGCC is distributed in the hope that it will be useful, 1350397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1450397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1550397SobrienLibrary General Public License for more details. 1650397Sobrien 1750397SobrienYou should have received a copy of the GNU Library General Public 1850397SobrienLicense along with GCC; see the file COPYING. If not, write to the Free 19169689SkanSoftware Foundation, Inc., 51 Franklin Street, Fifth Floor, 20169689SkanBoston, MA 02110-1301, USA. */ 2150397Sobrien 2250397Sobrien/* This file contains routines to update a path, both to canonicalize 2350397Sobrien the directory format and to handle any prefix translation. 2450397Sobrien 2550397Sobrien This file must be compiled with -DPREFIX= to specify the "prefix" 2650397Sobrien value used by configure. If a filename does not begin with this 2750397Sobrien prefix, it will not be affected other than by directory canonicalization. 2850397Sobrien 2950397Sobrien Each caller of 'update_path' may specify both a filename and 3050397Sobrien a translation prefix and consist of the name of the package that contains 3150397Sobrien the file ("@GCC", "@BINUTIL", "@GNU", etc). 3250397Sobrien 3350397Sobrien If the prefix is not specified, the filename will only undergo 3450397Sobrien directory canonicalization. 3550397Sobrien 3650397Sobrien If it is specified, the string given by PREFIX will be replaced 3750397Sobrien by the specified prefix (with a '@' in front unless the prefix begins 3850397Sobrien with a '$') and further translation will be done as follows 3950397Sobrien until none of the two conditions below are met: 4050397Sobrien 4150397Sobrien 1) If the filename begins with '@', the string between the '@' and 4250397Sobrien the end of the name or the first '/' or directory separator will 4350397Sobrien be considered a "key" and looked up as follows: 4450397Sobrien 4550397Sobrien -- If this is a Win32 OS, then the Registry will be examined for 46117395Skan an entry of "key" in 4750397Sobrien 4890075Sobrien HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY> 4950397Sobrien 5090075Sobrien if found, that value will be used. <KEY> defaults to GCC version 5190075Sobrien string, but can be overridden at configuration time. 5250397Sobrien 5350397Sobrien -- If not found (or not a Win32 OS), the environment variable 5450397Sobrien key_ROOT (the value of "key" concatenated with the constant "_ROOT") 5550397Sobrien is tried. If that fails, then PREFIX (see above) is used. 5650397Sobrien 5750397Sobrien 2) If the filename begins with a '$', the rest of the string up 5850397Sobrien to the end or the first '/' or directory separator will be used 5950397Sobrien as an environment variable, whose value will be returned. 6050397Sobrien 6150397Sobrien Once all this is done, any '/' will be converted to DIR_SEPARATOR, 62117395Skan if they are different. 6350397Sobrien 6450397Sobrien NOTE: using resolve_keyed_path under Win32 requires linking with 6550397Sobrien advapi32.dll. */ 6650397Sobrien 6750397Sobrien 6850397Sobrien#include "config.h" 6950397Sobrien#include "system.h" 70132718Skan#include "coretypes.h" 71132718Skan#include "tm.h" 7290075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 7350397Sobrien#include <windows.h> 7450397Sobrien#endif 7552284Sobrien#include "prefix.h" 7650397Sobrien 7752284Sobrienstatic const char *std_prefix = PREFIX; 7850397Sobrien 79132718Skanstatic const char *get_key_value (char *); 80132718Skanstatic char *translate_name (char *); 81132718Skanstatic char *save_string (const char *, int); 82132718Skanstatic void tr (char *, int, int); 8350397Sobrien 8490075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 85132718Skanstatic char *lookup_key (char *); 8650397Sobrienstatic HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE; 8750397Sobrien#endif 8850397Sobrien 8950397Sobrien/* Given KEY, as above, return its value. */ 9050397Sobrien 9152284Sobrienstatic const char * 92132718Skanget_key_value (char *key) 9350397Sobrien{ 9452284Sobrien const char *prefix = 0; 9550397Sobrien char *temp = 0; 9650397Sobrien 9790075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 9850397Sobrien prefix = lookup_key (key); 9950397Sobrien#endif 10050397Sobrien 10150397Sobrien if (prefix == 0) 10290075Sobrien prefix = getenv (temp = concat (key, "_ROOT", NULL)); 10350397Sobrien 10450397Sobrien if (prefix == 0) 10550397Sobrien prefix = std_prefix; 10650397Sobrien 10750397Sobrien if (temp) 10850397Sobrien free (temp); 10950397Sobrien 11050397Sobrien return prefix; 11150397Sobrien} 11250397Sobrien 11350397Sobrien/* Return a copy of a string that has been placed in the heap. */ 11450397Sobrien 11550397Sobrienstatic char * 116132718Skansave_string (const char *s, int len) 11750397Sobrien{ 118169689Skan char *result = XNEWVEC (char, len + 1); 11950397Sobrien 12090075Sobrien memcpy (result, s, len); 12150397Sobrien result[len] = 0; 12250397Sobrien return result; 12350397Sobrien} 12450397Sobrien 12590075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) 12650397Sobrien 127169689Skan#ifndef WIN32_REGISTRY_KEY 128169689Skan# define WIN32_REGISTRY_KEY BASEVER 129169689Skan#endif 130169689Skan 13150397Sobrien/* Look up "key" in the registry, as above. */ 13250397Sobrien 13350397Sobrienstatic char * 134132718Skanlookup_key (char *key) 13550397Sobrien{ 13650397Sobrien char *dst; 13750397Sobrien DWORD size; 13850397Sobrien DWORD type; 13950397Sobrien LONG res; 14050397Sobrien 14150397Sobrien if (reg_key == (HKEY) INVALID_HANDLE_VALUE) 14250397Sobrien { 14350397Sobrien res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, 14450397Sobrien KEY_READ, ®_key); 14550397Sobrien 14650397Sobrien if (res == ERROR_SUCCESS) 14750397Sobrien res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0, 14850397Sobrien KEY_READ, ®_key); 14950397Sobrien 15090075Sobrien if (res == ERROR_SUCCESS) 15190075Sobrien res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0, 15290075Sobrien KEY_READ, ®_key); 15390075Sobrien 15450397Sobrien if (res != ERROR_SUCCESS) 155117395Skan { 156117395Skan reg_key = (HKEY) INVALID_HANDLE_VALUE; 157117395Skan return 0; 158117395Skan } 15950397Sobrien } 16050397Sobrien 16150397Sobrien size = 32; 162132718Skan dst = xmalloc (size); 16350397Sobrien 164169689Skan res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); 16550397Sobrien if (res == ERROR_MORE_DATA && type == REG_SZ) 16650397Sobrien { 167132718Skan dst = xrealloc (dst, size); 168169689Skan res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size); 16950397Sobrien } 17050397Sobrien 17150397Sobrien if (type != REG_SZ || res != ERROR_SUCCESS) 17250397Sobrien { 17350397Sobrien free (dst); 17450397Sobrien dst = 0; 17550397Sobrien } 17650397Sobrien 17750397Sobrien return dst; 17850397Sobrien} 17950397Sobrien#endif 18050397Sobrien 18190075Sobrien/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the 18290075Sobrien translation rules above and return a newly malloc-ed name. 18390075Sobrien Otherwise, return the given name. */ 18450397Sobrien 18590075Sobrienstatic char * 186132718Skantranslate_name (char *name) 18750397Sobrien{ 18890075Sobrien char code; 18990075Sobrien char *key, *old_name; 19090075Sobrien const char *prefix; 19150397Sobrien int keylen; 19250397Sobrien 19390075Sobrien for (;;) 19490075Sobrien { 19590075Sobrien code = name[0]; 19690075Sobrien if (code != '@' && code != '$') 19790075Sobrien break; 19850397Sobrien 19990075Sobrien for (keylen = 0; 20090075Sobrien (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1])); 20190075Sobrien keylen++) 20290075Sobrien ; 20350397Sobrien 204169689Skan key = (char *) alloca (keylen + 1); 20590075Sobrien strncpy (key, &name[1], keylen); 20690075Sobrien key[keylen] = 0; 20750397Sobrien 20890075Sobrien if (code == '@') 20990075Sobrien { 21090075Sobrien prefix = get_key_value (key); 21190075Sobrien if (prefix == 0) 21290075Sobrien prefix = std_prefix; 21390075Sobrien } 21490075Sobrien else 21590075Sobrien prefix = getenv (key); 21650397Sobrien 21750397Sobrien if (prefix == 0) 21890075Sobrien prefix = PREFIX; 21990075Sobrien 22090075Sobrien /* We used to strip trailing DIR_SEPARATORs here, but that can 22190075Sobrien sometimes yield a result with no separator when one was coded 22290075Sobrien and intended by the user, causing two path components to run 22390075Sobrien together. */ 22490075Sobrien 22590075Sobrien old_name = name; 22690075Sobrien name = concat (prefix, &name[keylen + 1], NULL); 22790075Sobrien free (old_name); 22850397Sobrien } 22950397Sobrien 23090075Sobrien return name; 23190075Sobrien} 23250397Sobrien 23390075Sobrien/* In a NUL-terminated STRING, replace character C1 with C2 in-place. */ 23490075Sobrienstatic void 235132718Skantr (char *string, int c1, int c2) 23690075Sobrien{ 23790075Sobrien do 23850397Sobrien { 23990075Sobrien if (*string == c1) 24090075Sobrien *string = c2; 24150397Sobrien } 24290075Sobrien while (*string++); 24350397Sobrien} 24450397Sobrien 245169689Skan/* Update PATH using KEY if PATH starts with PREFIX as a directory. 246169689Skan The returned string is always malloc-ed, and the caller is 247169689Skan responsible for freeing it. */ 24850397Sobrien 24990075Sobrienchar * 250132718Skanupdate_path (const char *path, const char *key) 25150397Sobrien{ 252117395Skan char *result, *p; 253169689Skan const int len = strlen (std_prefix); 25490075Sobrien 255169689Skan if (! strncmp (path, std_prefix, len) 256169689Skan && (IS_DIR_SEPARATOR(path[len]) 257169689Skan || path[len] == '\0') 258169689Skan && key != 0) 25950397Sobrien { 26090075Sobrien bool free_key = false; 26190075Sobrien 26250397Sobrien if (key[0] != '$') 26390075Sobrien { 26490075Sobrien key = concat ("@", key, NULL); 26590075Sobrien free_key = true; 26690075Sobrien } 26750397Sobrien 268169689Skan result = concat (key, &path[len], NULL); 26990075Sobrien if (free_key) 27090075Sobrien free ((char *) key); 27190075Sobrien result = translate_name (result); 27250397Sobrien } 27390075Sobrien else 27490075Sobrien result = xstrdup (path); 27552284Sobrien 276117395Skan#ifndef ALWAYS_STRIP_DOTDOT 277117395Skan#define ALWAYS_STRIP_DOTDOT 0 278117395Skan#endif 279117395Skan 280117395Skan p = result; 281117395Skan while (1) 282117395Skan { 283117395Skan char *src, *dest; 284117395Skan 285117395Skan p = strchr (p, '.'); 286117395Skan if (p == NULL) 287117395Skan break; 288117395Skan /* Look for `/../' */ 289117395Skan if (p[1] == '.' 290117395Skan && IS_DIR_SEPARATOR (p[2]) 291117395Skan && (p != result && IS_DIR_SEPARATOR (p[-1]))) 292117395Skan { 293117395Skan *p = 0; 294117395Skan if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0) 295117395Skan { 296117395Skan *p = '.'; 297117395Skan break; 298117395Skan } 299117395Skan else 300117395Skan { 301117395Skan /* We can't access the dir, so we won't be able to 302117395Skan access dir/.. either. Strip out `dir/../'. If `dir' 303117395Skan turns out to be `.', strip one more path component. */ 304117395Skan dest = p; 305117395Skan do 306117395Skan { 307117395Skan --dest; 308117395Skan while (dest != result && IS_DIR_SEPARATOR (*dest)) 309117395Skan --dest; 310117395Skan while (dest != result && !IS_DIR_SEPARATOR (dest[-1])) 311117395Skan --dest; 312117395Skan } 313117395Skan while (dest != result && *dest == '.'); 314117395Skan /* If we have something like `./..' or `/..', don't 315117395Skan strip anything more. */ 316117395Skan if (*dest == '.' || IS_DIR_SEPARATOR (*dest)) 317117395Skan { 318117395Skan *p = '.'; 319117395Skan break; 320117395Skan } 321117395Skan src = p + 3; 322117395Skan while (IS_DIR_SEPARATOR (*src)) 323117395Skan ++src; 324117395Skan p = dest; 325117395Skan while ((*dest++ = *src++) != 0) 326117395Skan ; 327117395Skan } 328117395Skan } 329117395Skan else 330117395Skan ++p; 331117395Skan } 332117395Skan 33390075Sobrien#ifdef UPDATE_PATH_HOST_CANONICALIZE 33490075Sobrien /* Perform host dependent canonicalization when needed. */ 335117395Skan UPDATE_PATH_HOST_CANONICALIZE (result); 33690075Sobrien#endif 33790075Sobrien 33852284Sobrien#ifdef DIR_SEPARATOR_2 33990075Sobrien /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */ 34090075Sobrien if (DIR_SEPARATOR_2 != DIR_SEPARATOR) 34190075Sobrien tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR); 34252284Sobrien#endif 34390075Sobrien 34452284Sobrien#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2) 34550397Sobrien if (DIR_SEPARATOR != '/') 34690075Sobrien tr (result, '/', DIR_SEPARATOR); 34750397Sobrien#endif 34850397Sobrien 34990075Sobrien return result; 35050397Sobrien} 35150397Sobrien 352132718Skan/* Reset the standard prefix. */ 35350397Sobrienvoid 354132718Skanset_std_prefix (const char *prefix, int len) 35550397Sobrien{ 35650397Sobrien std_prefix = save_string (prefix, len); 35750397Sobrien} 358