xref: /dragonfly/contrib/gcc-8.0/gcc/prefix.c (revision 38fd1498)
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, &reg_key);
142*38fd1498Szrj 
143*38fd1498Szrj       if (res == ERROR_SUCCESS)
144*38fd1498Szrj 	res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
145*38fd1498Szrj 			     KEY_READ, &reg_key);
146*38fd1498Szrj 
147*38fd1498Szrj       if (res == ERROR_SUCCESS)
148*38fd1498Szrj 	res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
149*38fd1498Szrj 			     KEY_READ, &reg_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