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