]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/prefix.c
* jump.c: Convert prototypes to ISO C90.
[thirdparty/gcc.git] / gcc / prefix.c
CommitLineData
03b352a9 1/* Utility to update paths from internal to external forms.
3ad4992f 2 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
38475ee3 3 Free Software Foundation, Inc.
03b352a9 4
f12b58b3 5This file is part of GCC.
03b352a9 6
f12b58b3 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.
03b352a9 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
195731ad 46 an entry of "key" in
03b352a9 47
778a2833 48 HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY>
03b352a9 49
778a2833 50 if found, that value will be used. <KEY> defaults to GCC version
51 string, but can be overridden at configuration time.
03b352a9 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,
195731ad 62 if they are different.
03b352a9 63
64 NOTE: using resolve_keyed_path under Win32 requires linking with
65 advapi32.dll. */
66
67
68#include "config.h"
405711de 69#include "system.h"
805e22b2 70#include "coretypes.h"
71#include "tm.h"
778a2833 72#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
03b352a9 73#include <windows.h>
74#endif
7bcdc3c7 75#include "prefix.h"
03b352a9 76
7bcdc3c7 77static const char *std_prefix = PREFIX;
055237ef 78
3ad4992f 79static const char *get_key_value (char *);
80static char *translate_name (char *);
81static char *save_string (const char *, int);
82static void tr (char *, int, int);
03b352a9 83
778a2833 84#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
3ad4992f 85static char *lookup_key (char *);
03b352a9 86static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
87#endif
88
03b352a9 89/* Given KEY, as above, return its value. */
90
7bcdc3c7 91static const char *
3ad4992f 92get_key_value (char *key)
03b352a9 93{
7bcdc3c7 94 const char *prefix = 0;
055237ef 95 char *temp = 0;
03b352a9 96
778a2833 97#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
03b352a9 98 prefix = lookup_key (key);
99#endif
100
101 if (prefix == 0)
4e2023c8 102 prefix = getenv (temp = concat (key, "_ROOT", NULL));
03b352a9 103
104 if (prefix == 0)
055237ef 105 prefix = std_prefix;
106
107 if (temp)
108 free (temp);
03b352a9 109
110 return prefix;
111}
112
03b352a9 113/* Return a copy of a string that has been placed in the heap. */
114
115static char *
3ad4992f 116save_string (const char *s, int len)
03b352a9 117{
19cb6b50 118 char *result = xmalloc (len + 1);
03b352a9 119
b1b63592 120 memcpy (result, s, len);
03b352a9 121 result[len] = 0;
122 return result;
123}
124
778a2833 125#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
03b352a9 126
127/* Look up "key" in the registry, as above. */
128
129static char *
3ad4992f 130lookup_key (char *key)
03b352a9 131{
132 char *dst;
133 DWORD size;
134 DWORD type;
135 LONG res;
136
137 if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
138 {
139 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
140 KEY_READ, &reg_key);
141
142 if (res == ERROR_SUCCESS)
143 res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
144 KEY_READ, &reg_key);
145
778a2833 146 if (res == ERROR_SUCCESS)
147 res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
148 KEY_READ, &reg_key);
149
03b352a9 150 if (res != ERROR_SUCCESS)
195731ad 151 {
152 reg_key = (HKEY) INVALID_HANDLE_VALUE;
153 return 0;
154 }
03b352a9 155 }
156
157 size = 32;
779740c5 158 dst = (char *) xmalloc (size);
03b352a9 159
160 res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
161 if (res == ERROR_MORE_DATA && type == REG_SZ)
162 {
779740c5 163 dst = (char *) xrealloc (dst, size);
03b352a9 164 res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
165 }
166
167 if (type != REG_SZ || res != ERROR_SUCCESS)
168 {
169 free (dst);
170 dst = 0;
171 }
172
173 return dst;
174}
175#endif
176
17b80c08 177/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
178 translation rules above and return a newly malloc-ed name.
179 Otherwise, return the given name. */
03b352a9 180
17b80c08 181static char *
3ad4992f 182translate_name (char *name)
03b352a9 183{
17b80c08 184 char code;
185 char *key, *old_name;
186 const char *prefix;
03b352a9 187 int keylen;
188
17b80c08 189 for (;;)
190 {
191 code = name[0];
192 if (code != '@' && code != '$')
193 break;
194
195 for (keylen = 0;
196 (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
197 keylen++)
198 ;
199
200 key = (char *) alloca (keylen + 1);
201 strncpy (key, &name[1], keylen);
202 key[keylen] = 0;
203
204 if (code == '@')
205 {
206 prefix = get_key_value (key);
207 if (prefix == 0)
208 prefix = std_prefix;
209 }
210 else
211 prefix = getenv (key);
03b352a9 212
17b80c08 213 if (prefix == 0)
214 prefix = PREFIX;
03b352a9 215
17b80c08 216 /* We used to strip trailing DIR_SEPARATORs here, but that can
217 sometimes yield a result with no separator when one was coded
218 and intended by the user, causing two path components to run
219 together. */
03b352a9 220
17b80c08 221 old_name = name;
222 name = concat (prefix, &name[keylen + 1], NULL);
223 free (old_name);
03b352a9 224 }
997d68fe 225
17b80c08 226 return name;
227}
03b352a9 228
17b80c08 229/* In a NUL-terminated STRING, replace character C1 with C2 in-place. */
230static void
3ad4992f 231tr (char *string, int c1, int c2)
17b80c08 232{
233 do
234 {
235 if (*string == c1)
236 *string = c2;
237 }
238 while (*string++);
03b352a9 239}
240
17b80c08 241/* Update PATH using KEY if PATH starts with PREFIX. The returned
242 string is always malloc-ed, and the caller is responsible for
243 freeing it. */
03b352a9 244
17b80c08 245char *
3ad4992f 246update_path (const char *path, const char *key)
03b352a9 247{
38475ee3 248 char *result, *p;
17b80c08 249
055237ef 250 if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
03b352a9 251 {
17b80c08 252 bool free_key = false;
03b352a9 253
17b80c08 254 if (key[0] != '$')
255 {
256 key = concat ("@", key, NULL);
257 free_key = true;
258 }
259
260 result = concat (key, &path[strlen (std_prefix)], NULL);
261 if (free_key)
262 free ((char *) key);
263 result = translate_name (result);
03b352a9 264 }
17b80c08 265 else
266 result = xstrdup (path);
79b23a1e 267
38475ee3 268#ifndef ALWAYS_STRIP_DOTDOT
269#define ALWAYS_STRIP_DOTDOT 0
270#endif
271
272 p = result;
273 while (1)
274 {
275 char *src, *dest;
276
277 p = strchr (p, '.');
278 if (p == NULL)
279 break;
38475ee3 280 /* Look for `/../' */
fa93416c 281 if (p[1] == '.'
282 && IS_DIR_SEPARATOR (p[2])
283 && (p != result && IS_DIR_SEPARATOR (p[-1])))
38475ee3 284 {
285 *p = 0;
286 if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
287 {
288 *p = '.';
fa93416c 289 break;
38475ee3 290 }
291 else
292 {
293 /* We can't access the dir, so we won't be able to
fa93416c 294 access dir/.. either. Strip out `dir/../'. If `dir'
295 turns out to be `.', strip one more path component. */
296 dest = p;
297 do
298 {
299 --dest;
300 while (dest != result && IS_DIR_SEPARATOR (*dest))
301 --dest;
302 while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
303 --dest;
304 }
305 while (dest != result && *dest == '.');
306 /* If we have something like `./..' or `/..', don't
307 strip anything more. */
308 if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
309 {
310 *p = '.';
311 break;
312 }
38475ee3 313 src = p + 3;
314 while (IS_DIR_SEPARATOR (*src))
315 ++src;
316 p = dest;
317 while ((*dest++ = *src++) != 0)
318 ;
319 }
320 }
321 else
322 ++p;
323 }
324
4e79af62 325#ifdef UPDATE_PATH_HOST_CANONICALIZE
17b80c08 326 /* Perform host dependent canonicalization when needed. */
38475ee3 327 UPDATE_PATH_HOST_CANONICALIZE (result);
4e79af62 328#endif
329
79b23a1e 330#ifdef DIR_SEPARATOR_2
aa40f561 331 /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */
17b80c08 332 if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
333 tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
79b23a1e 334#endif
17b80c08 335
79b23a1e 336#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
03b352a9 337 if (DIR_SEPARATOR != '/')
17b80c08 338 tr (result, '/', DIR_SEPARATOR);
03b352a9 339#endif
340
17b80c08 341 return result;
03b352a9 342}
055237ef 343
2358393e 344/* Reset the standard prefix. */
055237ef 345void
3ad4992f 346set_std_prefix (const char *prefix, int len)
055237ef 347{
348 std_prefix = save_string (prefix, len);
349}