prefix.c revision 225736
113840Swosch/* Utility to update paths from internal to external forms.
213840Swosch   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
313840Swosch   Free Software Foundation, Inc.
413840Swosch
513840SwoschThis file is part of GCC.
613840Swosch
713840SwoschGCC is free software; you can redistribute it and/or modify it under
813840Swoschthe terms of the GNU Library General Public License as published by
913840Swoschthe Free Software Foundation; either version 2 of the License, or (at
1013840Swoschyour option) any later version.
1113840Swosch
1213840SwoschGCC is distributed in the hope that it will be useful,
1313840Swoschbut WITHOUT ANY WARRANTY; without even the implied warranty of
1413840SwoschMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1513840SwoschLibrary General Public License for more details.
1613840Swosch
1713840SwoschYou should have received a copy of the GNU Library General Public
1813840SwoschLicense along with GCC; see the file COPYING.  If not, write to the Free
1913840SwoschSoftware Foundation, Inc., 51 Franklin Street, Fifth Floor,
2013840SwoschBoston, MA 02110-1301, USA.  */
2113840Swosch
2213840Swosch/* This file contains routines to update a path, both to canonicalize
2313840Swosch   the directory format and to handle any prefix translation.
2413840Swosch
2513840Swosch   This file must be compiled with -DPREFIX= to specify the "prefix"
2613840Swosch   value used by configure.  If a filename does not begin with this
2713840Swosch   prefix, it will not be affected other than by directory canonicalization.
2813840Swosch
2913840Swosch   Each caller of 'update_path' may specify both a filename and
3013840Swosch   a translation prefix and consist of the name of the package that contains
3113840Swosch   the file ("@GCC", "@BINUTIL", "@GNU", etc).
3213840Swosch
3313840Swosch   If the prefix is not specified, the filename will only undergo
3413840Swosch   directory canonicalization.
3513840Swosch
3613840Swosch   If it is specified, the string given by PREFIX will be replaced
3713840Swosch   by the specified prefix (with a '@' in front unless the prefix begins
3813840Swosch   with a '$') and further translation will be done as follows
3913840Swosch   until none of the two conditions below are met:
4013840Swosch
4113840Swosch   1) If the filename begins with '@', the string between the '@' and
4213840Swosch   the end of the name or the first '/' or directory separator will
4313840Swosch   be considered a "key" and looked up as follows:
4413840Swosch
4513840Swosch   -- If this is a Win32 OS, then the Registry will be examined for
4613840Swosch      an entry of "key" in
4713840Swosch
4813840Swosch      HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY>
4913840Swosch
5013840Swosch      if found, that value will be used. <KEY> defaults to GCC version
5113840Swosch      string, but can be overridden at configuration time.
5213840Swosch
5313840Swosch   -- If not found (or not a Win32 OS), the environment variable
5413840Swosch      key_ROOT (the value of "key" concatenated with the constant "_ROOT")
5513840Swosch      is tried.  If that fails, then PREFIX (see above) is used.
5613840Swosch
5713840Swosch   2) If the filename begins with a '$', the rest of the string up
5813840Swosch   to the end or the first '/' or directory separator will be used
5913840Swosch   as an environment variable, whose value will be returned.
6013840Swosch
6113840Swosch   Once all this is done, any '/' will be converted to DIR_SEPARATOR,
6213840Swosch   if they are different.
6313840Swosch
6413840Swosch   NOTE:  using resolve_keyed_path under Win32 requires linking with
6513840Swosch   advapi32.dll.  */
6613840Swosch
6713840Swosch
6813840Swosch#include "config.h"
6913840Swosch#include "system.h"
7013840Swosch#include "coretypes.h"
7113840Swosch#include "tm.h"
7213840Swosch#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
7313840Swosch#include <windows.h>
7413840Swosch#endif
7513840Swosch#include "prefix.h"
7613840Swosch
7713840Swoschstatic const char *std_prefix = PREFIX;
7813840Swosch
7913840Swoschstatic const char *get_key_value (char *);
8013840Swoschstatic char *translate_name (char *);
8113840Swoschstatic char *save_string (const char *, int);
8213840Swoschstatic void tr (char *, int, int);
8313840Swosch
8413840Swosch#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
8513840Swoschstatic char *lookup_key (char *);
8613840Swoschstatic HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
8713840Swosch#endif
8813840Swosch
8913840Swosch/* Given KEY, as above, return its value.  */
9013840Swosch
9113840Swoschstatic const char *
9213840Swoschget_key_value (char *key)
9313840Swosch{
9413840Swosch  const char *prefix = 0;
95  char *temp = 0;
96
97#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
98  prefix = lookup_key (key);
99#endif
100
101  if (prefix == 0)
102    prefix = getenv (temp = concat (key, "_ROOT", NULL));
103
104  if (prefix == 0)
105    prefix = std_prefix;
106
107  if (temp)
108    free (temp);
109
110  return prefix;
111}
112
113/* Return a copy of a string that has been placed in the heap.  */
114
115static char *
116save_string (const char *s, int len)
117{
118  char *result = XNEWVEC (char, len + 1);
119
120  memcpy (result, s, len);
121  result[len] = 0;
122  return result;
123}
124
125#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
126
127#ifndef WIN32_REGISTRY_KEY
128# define WIN32_REGISTRY_KEY BASEVER
129#endif
130
131/* Look up "key" in the registry, as above.  */
132
133static char *
134lookup_key (char *key)
135{
136  char *dst;
137  DWORD size;
138  DWORD type;
139  LONG res;
140
141  if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
142    {
143      res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
144			   KEY_READ, &reg_key);
145
146      if (res == ERROR_SUCCESS)
147	res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
148			     KEY_READ, &reg_key);
149
150      if (res == ERROR_SUCCESS)
151	res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
152			     KEY_READ, &reg_key);
153
154      if (res != ERROR_SUCCESS)
155	{
156	  reg_key = (HKEY) INVALID_HANDLE_VALUE;
157	  return 0;
158	}
159    }
160
161  size = 32;
162  dst = xmalloc (size);
163
164  res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
165  if (res == ERROR_MORE_DATA && type == REG_SZ)
166    {
167      dst = xrealloc (dst, size);
168      res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
169    }
170
171  if (type != REG_SZ || res != ERROR_SUCCESS)
172    {
173      free (dst);
174      dst = 0;
175    }
176
177  return dst;
178}
179#endif
180
181/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
182   translation rules above and return a newly malloc-ed name.
183   Otherwise, return the given name.  */
184
185static char *
186translate_name (char *name)
187{
188  char code;
189  char *key, *old_name;
190  const char *prefix;
191  int keylen;
192
193  for (;;)
194    {
195      code = name[0];
196      if (code != '@' && code != '$')
197	break;
198
199      for (keylen = 0;
200	   (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
201	   keylen++)
202	;
203
204      key = (char *) alloca (keylen + 1);
205      strncpy (key, &name[1], keylen);
206      key[keylen] = 0;
207
208      if (code == '@')
209	{
210	  prefix = get_key_value (key);
211	  if (prefix == 0)
212	    prefix = std_prefix;
213	}
214      else
215	prefix = getenv (key);
216
217      if (prefix == 0)
218	prefix = PREFIX;
219
220      /* We used to strip trailing DIR_SEPARATORs here, but that can
221	 sometimes yield a result with no separator when one was coded
222	 and intended by the user, causing two path components to run
223	 together.  */
224
225      old_name = name;
226      name = concat (prefix, &name[keylen + 1], NULL);
227      free (old_name);
228    }
229
230  return name;
231}
232
233/* In a NUL-terminated STRING, replace character C1 with C2 in-place.  */
234static void
235tr (char *string, int c1, int c2)
236{
237  do
238    {
239      if (*string == c1)
240	*string = c2;
241    }
242  while (*string++);
243}
244
245/* Update PATH using KEY if PATH starts with PREFIX as a directory.
246   The returned string is always malloc-ed, and the caller is
247   responsible for freeing it.  */
248
249char *
250update_path (const char *path, const char *key)
251{
252  char *result, *p;
253  const int len = strlen (std_prefix);
254
255  if (! strncmp (path, std_prefix, len)
256      && (IS_DIR_SEPARATOR(path[len])
257          || path[len] == '\0')
258      && key != 0)
259    {
260      bool free_key = false;
261
262      if (key[0] != '$')
263	{
264	  key = concat ("@", key, NULL);
265	  free_key = true;
266	}
267
268      result = concat (key, &path[len], NULL);
269      if (free_key)
270	free ((char *) key);
271      result = translate_name (result);
272    }
273  else
274    result = xstrdup (path);
275
276#ifndef ALWAYS_STRIP_DOTDOT
277#define ALWAYS_STRIP_DOTDOT 0
278#endif
279
280  p = result;
281  while (1)
282    {
283      char *src, *dest;
284
285      p = strchr (p, '.');
286      if (p == NULL)
287	break;
288      /* Look for `/../'  */
289      if (p[1] == '.'
290	  && IS_DIR_SEPARATOR (p[2])
291	  && (p != result && IS_DIR_SEPARATOR (p[-1])))
292	{
293	  *p = 0;
294	  if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
295	    {
296	      *p = '.';
297	      break;
298	    }
299	  else
300	    {
301	      /* We can't access the dir, so we won't be able to
302		 access dir/.. either.  Strip out `dir/../'.  If `dir'
303		 turns out to be `.', strip one more path component.  */
304	      dest = p;
305	      do
306		{
307		  --dest;
308		  while (dest != result && IS_DIR_SEPARATOR (*dest))
309		    --dest;
310		  while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
311		    --dest;
312		}
313	      while (dest != result && *dest == '.');
314	      /* If we have something like `./..' or `/..', don't
315		 strip anything more.  */
316	      if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
317		{
318		  *p = '.';
319		  break;
320		}
321	      src = p + 3;
322	      while (IS_DIR_SEPARATOR (*src))
323		++src;
324	      p = dest;
325	      while ((*dest++ = *src++) != 0)
326		;
327	    }
328	}
329      else
330	++p;
331    }
332
333#ifdef UPDATE_PATH_HOST_CANONICALIZE
334  /* Perform host dependent canonicalization when needed.  */
335  UPDATE_PATH_HOST_CANONICALIZE (result);
336#endif
337
338#ifdef DIR_SEPARATOR_2
339  /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR.  */
340  if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
341    tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
342#endif
343
344#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
345  if (DIR_SEPARATOR != '/')
346    tr (result, '/', DIR_SEPARATOR);
347#endif
348
349  return result;
350}
351
352/* Reset the standard prefix.  */
353void
354set_std_prefix (const char *prefix, int len)
355{
356  std_prefix = save_string (prefix, len);
357}
358