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