]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/prefix.c
Change copyright header to refer to version 3 of the GNU General Public License and...
[thirdparty/gcc.git] / gcc / prefix.c
CommitLineData
4a5121b5 1/* Utility to update paths from internal to external forms.
9dcd6f09
NC
2 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2007 Free Software Foundation, Inc.
4a5121b5 4
1322177d 5This file is part of GCC.
4a5121b5 6
1322177d
LB
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU Library General Public License as published by
9dcd6f09 9the Free Software Foundation; either version 3 of the License, or (at
1322177d 10your option) any later version.
4a5121b5
JL
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15Library General Public License for more details.
16
17You should have received a copy of the GNU Library General Public
9dcd6f09
NC
18License along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
4a5121b5
JL
20
21/* This file contains routines to update a path, both to canonicalize
22 the directory format and to handle any prefix translation.
23
24 This file must be compiled with -DPREFIX= to specify the "prefix"
25 value used by configure. If a filename does not begin with this
26 prefix, it will not be affected other than by directory canonicalization.
27
28 Each caller of 'update_path' may specify both a filename and
29 a translation prefix and consist of the name of the package that contains
30 the file ("@GCC", "@BINUTIL", "@GNU", etc).
31
32 If the prefix is not specified, the filename will only undergo
33 directory canonicalization.
34
35 If it is specified, the string given by PREFIX will be replaced
36 by the specified prefix (with a '@' in front unless the prefix begins
37 with a '$') and further translation will be done as follows
38 until none of the two conditions below are met:
39
40 1) If the filename begins with '@', the string between the '@' and
41 the end of the name or the first '/' or directory separator will
42 be considered a "key" and looked up as follows:
43
44 -- If this is a Win32 OS, then the Registry will be examined for
6a4d6760 45 an entry of "key" in
4a5121b5 46
f4ab28e3 47 HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY>
4a5121b5 48
f4ab28e3
MK
49 if found, that value will be used. <KEY> defaults to GCC version
50 string, but can be overridden at configuration time.
4a5121b5
JL
51
52 -- If not found (or not a Win32 OS), the environment variable
53 key_ROOT (the value of "key" concatenated with the constant "_ROOT")
54 is tried. If that fails, then PREFIX (see above) is used.
55
56 2) If the filename begins with a '$', the rest of the string up
57 to the end or the first '/' or directory separator will be used
58 as an environment variable, whose value will be returned.
59
60 Once all this is done, any '/' will be converted to DIR_SEPARATOR,
6a4d6760 61 if they are different.
4a5121b5
JL
62
63 NOTE: using resolve_keyed_path under Win32 requires linking with
64 advapi32.dll. */
65
66
67#include "config.h"
670ee920 68#include "system.h"
4977bab6
ZW
69#include "coretypes.h"
70#include "tm.h"
f4ab28e3 71#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
4a5121b5
JL
72#include <windows.h>
73#endif
460ee112 74#include "prefix.h"
4a5121b5 75
460ee112 76static const char *std_prefix = PREFIX;
6ed4bb9a 77
0c20a65f
AJ
78static const char *get_key_value (char *);
79static char *translate_name (char *);
80static char *save_string (const char *, int);
81static void tr (char *, int, int);
4a5121b5 82
f4ab28e3 83#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
0c20a65f 84static char *lookup_key (char *);
4a5121b5
JL
85static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
86#endif
87
4a5121b5
JL
88/* Given KEY, as above, return its value. */
89
460ee112 90static const char *
0c20a65f 91get_key_value (char *key)
4a5121b5 92{
460ee112 93 const char *prefix = 0;
6ed4bb9a 94 char *temp = 0;
4a5121b5 95
f4ab28e3 96#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
4a5121b5
JL
97 prefix = lookup_key (key);
98#endif
99
100 if (prefix == 0)
d4f2852f 101 prefix = getenv (temp = concat (key, "_ROOT", NULL));
4a5121b5
JL
102
103 if (prefix == 0)
6ed4bb9a
MM
104 prefix = std_prefix;
105
106 if (temp)
107 free (temp);
4a5121b5
JL
108
109 return prefix;
110}
111
4a5121b5
JL
112/* Return a copy of a string that has been placed in the heap. */
113
114static char *
0c20a65f 115save_string (const char *s, int len)
4a5121b5 116{
cceb1885 117 char *result = XNEWVEC (char, len + 1);
4a5121b5 118
4e135bdd 119 memcpy (result, s, len);
4a5121b5
JL
120 result[len] = 0;
121 return result;
122}
123
f4ab28e3 124#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
4a5121b5 125
a1286ef5
ZW
126#ifndef WIN32_REGISTRY_KEY
127# define WIN32_REGISTRY_KEY BASEVER
128#endif
129
4a5121b5
JL
130/* Look up "key" in the registry, as above. */
131
132static char *
0c20a65f 133lookup_key (char *key)
4a5121b5
JL
134{
135 char *dst;
136 DWORD size;
137 DWORD type;
138 LONG res;
139
140 if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
141 {
142 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
143 KEY_READ, &reg_key);
144
145 if (res == ERROR_SUCCESS)
146 res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
147 KEY_READ, &reg_key);
148
f4ab28e3
MK
149 if (res == ERROR_SUCCESS)
150 res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
151 KEY_READ, &reg_key);
152
4a5121b5 153 if (res != ERROR_SUCCESS)
6a4d6760
KH
154 {
155 reg_key = (HKEY) INVALID_HANDLE_VALUE;
156 return 0;
157 }
4a5121b5
JL
158 }
159
160 size = 32;
703ad42b 161 dst = xmalloc (size);
4a5121b5 162
aff982b1 163 res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
4a5121b5
JL
164 if (res == ERROR_MORE_DATA && type == REG_SZ)
165 {
703ad42b 166 dst = xrealloc (dst, size);
aff982b1 167 res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
4a5121b5
JL
168 }
169
170 if (type != REG_SZ || res != ERROR_SUCCESS)
171 {
172 free (dst);
173 dst = 0;
174 }
175
176 return dst;
177}
178#endif
179
51c04256
NB
180/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
181 translation rules above and return a newly malloc-ed name.
182 Otherwise, return the given name. */
4a5121b5 183
51c04256 184static char *
0c20a65f 185translate_name (char *name)
4a5121b5 186{
51c04256
NB
187 char code;
188 char *key, *old_name;
189 const char *prefix;
4a5121b5
JL
190 int keylen;
191
51c04256
NB
192 for (;;)
193 {
194 code = name[0];
195 if (code != '@' && code != '$')
196 break;
197
198 for (keylen = 0;
199 (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
200 keylen++)
201 ;
202
cceb1885 203 key = (char *) alloca (keylen + 1);
51c04256
NB
204 strncpy (key, &name[1], keylen);
205 key[keylen] = 0;
206
207 if (code == '@')
208 {
209 prefix = get_key_value (key);
210 if (prefix == 0)
211 prefix = std_prefix;
212 }
213 else
214 prefix = getenv (key);
4a5121b5 215
51c04256
NB
216 if (prefix == 0)
217 prefix = PREFIX;
4a5121b5 218
51c04256
NB
219 /* We used to strip trailing DIR_SEPARATORs here, but that can
220 sometimes yield a result with no separator when one was coded
221 and intended by the user, causing two path components to run
222 together. */
4a5121b5 223
51c04256
NB
224 old_name = name;
225 name = concat (prefix, &name[keylen + 1], NULL);
226 free (old_name);
4a5121b5 227 }
e5e809f4 228
51c04256
NB
229 return name;
230}
4a5121b5 231
51c04256
NB
232/* In a NUL-terminated STRING, replace character C1 with C2 in-place. */
233static void
0c20a65f 234tr (char *string, int c1, int c2)
51c04256
NB
235{
236 do
237 {
238 if (*string == c1)
239 *string = c2;
240 }
241 while (*string++);
4a5121b5
JL
242}
243
428d4d76
TQ
244/* Update PATH using KEY if PATH starts with PREFIX as a directory.
245 The returned string is always malloc-ed, and the caller is
246 responsible for freeing it. */
4a5121b5 247
51c04256 248char *
0c20a65f 249update_path (const char *path, const char *key)
4a5121b5 250{
f6f23ad2 251 char *result, *p;
428d4d76 252 const int len = strlen (std_prefix);
51c04256 253
428d4d76
TQ
254 if (! strncmp (path, std_prefix, len)
255 && (IS_DIR_SEPARATOR(path[len])
256 || path[len] == '\0')
257 && key != 0)
4a5121b5 258 {
51c04256 259 bool free_key = false;
4a5121b5 260
51c04256
NB
261 if (key[0] != '$')
262 {
263 key = concat ("@", key, NULL);
264 free_key = true;
265 }
266
428d4d76 267 result = concat (key, &path[len], NULL);
51c04256
NB
268 if (free_key)
269 free ((char *) key);
270 result = translate_name (result);
4a5121b5 271 }
51c04256
NB
272 else
273 result = xstrdup (path);
509781a4 274
f6f23ad2
AM
275#ifndef ALWAYS_STRIP_DOTDOT
276#define ALWAYS_STRIP_DOTDOT 0
277#endif
278
279 p = result;
280 while (1)
281 {
282 char *src, *dest;
283
284 p = strchr (p, '.');
285 if (p == NULL)
286 break;
f6f23ad2 287 /* Look for `/../' */
d4348177
AM
288 if (p[1] == '.'
289 && IS_DIR_SEPARATOR (p[2])
290 && (p != result && IS_DIR_SEPARATOR (p[-1])))
f6f23ad2
AM
291 {
292 *p = 0;
293 if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
294 {
295 *p = '.';
d4348177 296 break;
f6f23ad2
AM
297 }
298 else
299 {
300 /* We can't access the dir, so we won't be able to
d4348177
AM
301 access dir/.. either. Strip out `dir/../'. If `dir'
302 turns out to be `.', strip one more path component. */
303 dest = p;
304 do
305 {
306 --dest;
307 while (dest != result && IS_DIR_SEPARATOR (*dest))
308 --dest;
309 while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
310 --dest;
311 }
312 while (dest != result && *dest == '.');
313 /* If we have something like `./..' or `/..', don't
314 strip anything more. */
315 if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
316 {
317 *p = '.';
318 break;
319 }
f6f23ad2
AM
320 src = p + 3;
321 while (IS_DIR_SEPARATOR (*src))
322 ++src;
323 p = dest;
324 while ((*dest++ = *src++) != 0)
325 ;
326 }
327 }
328 else
329 ++p;
330 }
331
93284395 332#ifdef UPDATE_PATH_HOST_CANONICALIZE
51c04256 333 /* Perform host dependent canonicalization when needed. */
f6f23ad2 334 UPDATE_PATH_HOST_CANONICALIZE (result);
93284395
ME
335#endif
336
509781a4 337#ifdef DIR_SEPARATOR_2
dc297297 338 /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */
51c04256
NB
339 if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
340 tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
509781a4 341#endif
51c04256 342
509781a4 343#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
4a5121b5 344 if (DIR_SEPARATOR != '/')
51c04256 345 tr (result, '/', DIR_SEPARATOR);
4a5121b5
JL
346#endif
347
51c04256 348 return result;
4a5121b5 349}
6ed4bb9a 350
f9da5064 351/* Reset the standard prefix. */
6ed4bb9a 352void
0c20a65f 353set_std_prefix (const char *prefix, int len)
6ed4bb9a
MM
354{
355 std_prefix = save_string (prefix, len);
356}