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