xref: /dflybsd-src/contrib/gcc-4.7/gcc/prefix.c (revision 81fc95a5293ee307c688a350a3feb4734aaddbb4)
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, &reg_key);
143e4b17023SJohn Marino 
144e4b17023SJohn Marino       if (res == ERROR_SUCCESS)
145e4b17023SJohn Marino 	res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
146e4b17023SJohn Marino 			     KEY_READ, &reg_key);
147e4b17023SJohn Marino 
148e4b17023SJohn Marino       if (res == ERROR_SUCCESS)
149e4b17023SJohn Marino 	res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
150e4b17023SJohn Marino 			     KEY_READ, &reg_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