150397Sobrien/* Utility to update paths from internal to external forms.
2169689Skan   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3117395Skan   Free Software Foundation, Inc.
450397Sobrien
590075SobrienThis file is part of GCC.
650397Sobrien
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU Library General Public License as published by
990075Sobrienthe Free Software Foundation; either version 2 of the License, or (at
1090075Sobrienyour option) any later version.
1150397Sobrien
1250397SobrienGCC is distributed in the hope that it will be useful,
1350397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1450397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1550397SobrienLibrary General Public License for more details.
1650397Sobrien
1750397SobrienYou should have received a copy of the GNU Library General Public
1850397SobrienLicense along with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, Inc., 51 Franklin Street, Fifth Floor,
20169689SkanBoston, MA 02110-1301, USA.  */
2150397Sobrien
2250397Sobrien/* This file contains routines to update a path, both to canonicalize
2350397Sobrien   the directory format and to handle any prefix translation.
2450397Sobrien
2550397Sobrien   This file must be compiled with -DPREFIX= to specify the "prefix"
2650397Sobrien   value used by configure.  If a filename does not begin with this
2750397Sobrien   prefix, it will not be affected other than by directory canonicalization.
2850397Sobrien
2950397Sobrien   Each caller of 'update_path' may specify both a filename and
3050397Sobrien   a translation prefix and consist of the name of the package that contains
3150397Sobrien   the file ("@GCC", "@BINUTIL", "@GNU", etc).
3250397Sobrien
3350397Sobrien   If the prefix is not specified, the filename will only undergo
3450397Sobrien   directory canonicalization.
3550397Sobrien
3650397Sobrien   If it is specified, the string given by PREFIX will be replaced
3750397Sobrien   by the specified prefix (with a '@' in front unless the prefix begins
3850397Sobrien   with a '$') and further translation will be done as follows
3950397Sobrien   until none of the two conditions below are met:
4050397Sobrien
4150397Sobrien   1) If the filename begins with '@', the string between the '@' and
4250397Sobrien   the end of the name or the first '/' or directory separator will
4350397Sobrien   be considered a "key" and looked up as follows:
4450397Sobrien
4550397Sobrien   -- If this is a Win32 OS, then the Registry will be examined for
46117395Skan      an entry of "key" in
4750397Sobrien
4890075Sobrien      HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY>
4950397Sobrien
5090075Sobrien      if found, that value will be used. <KEY> defaults to GCC version
5190075Sobrien      string, but can be overridden at configuration time.
5250397Sobrien
5350397Sobrien   -- If not found (or not a Win32 OS), the environment variable
5450397Sobrien      key_ROOT (the value of "key" concatenated with the constant "_ROOT")
5550397Sobrien      is tried.  If that fails, then PREFIX (see above) is used.
5650397Sobrien
5750397Sobrien   2) If the filename begins with a '$', the rest of the string up
5850397Sobrien   to the end or the first '/' or directory separator will be used
5950397Sobrien   as an environment variable, whose value will be returned.
6050397Sobrien
6150397Sobrien   Once all this is done, any '/' will be converted to DIR_SEPARATOR,
62117395Skan   if they are different.
6350397Sobrien
6450397Sobrien   NOTE:  using resolve_keyed_path under Win32 requires linking with
6550397Sobrien   advapi32.dll.  */
6650397Sobrien
6750397Sobrien
6850397Sobrien#include "config.h"
6950397Sobrien#include "system.h"
70132718Skan#include "coretypes.h"
71132718Skan#include "tm.h"
7290075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
7350397Sobrien#include <windows.h>
7450397Sobrien#endif
7552284Sobrien#include "prefix.h"
7650397Sobrien
7752284Sobrienstatic const char *std_prefix = PREFIX;
7850397Sobrien
79132718Skanstatic const char *get_key_value (char *);
80132718Skanstatic char *translate_name (char *);
81132718Skanstatic char *save_string (const char *, int);
82132718Skanstatic void tr (char *, int, int);
8350397Sobrien
8490075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
85132718Skanstatic char *lookup_key (char *);
8650397Sobrienstatic HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
8750397Sobrien#endif
8850397Sobrien
8950397Sobrien/* Given KEY, as above, return its value.  */
9050397Sobrien
9152284Sobrienstatic const char *
92132718Skanget_key_value (char *key)
9350397Sobrien{
9452284Sobrien  const char *prefix = 0;
9550397Sobrien  char *temp = 0;
9650397Sobrien
9790075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
9850397Sobrien  prefix = lookup_key (key);
9950397Sobrien#endif
10050397Sobrien
10150397Sobrien  if (prefix == 0)
10290075Sobrien    prefix = getenv (temp = concat (key, "_ROOT", NULL));
10350397Sobrien
10450397Sobrien  if (prefix == 0)
10550397Sobrien    prefix = std_prefix;
10650397Sobrien
10750397Sobrien  if (temp)
10850397Sobrien    free (temp);
10950397Sobrien
11050397Sobrien  return prefix;
11150397Sobrien}
11250397Sobrien
11350397Sobrien/* Return a copy of a string that has been placed in the heap.  */
11450397Sobrien
11550397Sobrienstatic char *
116132718Skansave_string (const char *s, int len)
11750397Sobrien{
118169689Skan  char *result = XNEWVEC (char, len + 1);
11950397Sobrien
12090075Sobrien  memcpy (result, s, len);
12150397Sobrien  result[len] = 0;
12250397Sobrien  return result;
12350397Sobrien}
12450397Sobrien
12590075Sobrien#if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
12650397Sobrien
127169689Skan#ifndef WIN32_REGISTRY_KEY
128169689Skan# define WIN32_REGISTRY_KEY BASEVER
129169689Skan#endif
130169689Skan
13150397Sobrien/* Look up "key" in the registry, as above.  */
13250397Sobrien
13350397Sobrienstatic char *
134132718Skanlookup_key (char *key)
13550397Sobrien{
13650397Sobrien  char *dst;
13750397Sobrien  DWORD size;
13850397Sobrien  DWORD type;
13950397Sobrien  LONG res;
14050397Sobrien
14150397Sobrien  if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
14250397Sobrien    {
14350397Sobrien      res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
14450397Sobrien			   KEY_READ, &reg_key);
14550397Sobrien
14650397Sobrien      if (res == ERROR_SUCCESS)
14750397Sobrien	res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
14850397Sobrien			     KEY_READ, &reg_key);
14950397Sobrien
15090075Sobrien      if (res == ERROR_SUCCESS)
15190075Sobrien	res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
15290075Sobrien			     KEY_READ, &reg_key);
15390075Sobrien
15450397Sobrien      if (res != ERROR_SUCCESS)
155117395Skan	{
156117395Skan	  reg_key = (HKEY) INVALID_HANDLE_VALUE;
157117395Skan	  return 0;
158117395Skan	}
15950397Sobrien    }
16050397Sobrien
16150397Sobrien  size = 32;
162132718Skan  dst = xmalloc (size);
16350397Sobrien
164169689Skan  res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
16550397Sobrien  if (res == ERROR_MORE_DATA && type == REG_SZ)
16650397Sobrien    {
167132718Skan      dst = xrealloc (dst, size);
168169689Skan      res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
16950397Sobrien    }
17050397Sobrien
17150397Sobrien  if (type != REG_SZ || res != ERROR_SUCCESS)
17250397Sobrien    {
17350397Sobrien      free (dst);
17450397Sobrien      dst = 0;
17550397Sobrien    }
17650397Sobrien
17750397Sobrien  return dst;
17850397Sobrien}
17950397Sobrien#endif
18050397Sobrien
18190075Sobrien/* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
18290075Sobrien   translation rules above and return a newly malloc-ed name.
18390075Sobrien   Otherwise, return the given name.  */
18450397Sobrien
18590075Sobrienstatic char *
186132718Skantranslate_name (char *name)
18750397Sobrien{
18890075Sobrien  char code;
18990075Sobrien  char *key, *old_name;
19090075Sobrien  const char *prefix;
19150397Sobrien  int keylen;
19250397Sobrien
19390075Sobrien  for (;;)
19490075Sobrien    {
19590075Sobrien      code = name[0];
19690075Sobrien      if (code != '@' && code != '$')
19790075Sobrien	break;
19850397Sobrien
19990075Sobrien      for (keylen = 0;
20090075Sobrien	   (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
20190075Sobrien	   keylen++)
20290075Sobrien	;
20350397Sobrien
204169689Skan      key = (char *) alloca (keylen + 1);
20590075Sobrien      strncpy (key, &name[1], keylen);
20690075Sobrien      key[keylen] = 0;
20750397Sobrien
20890075Sobrien      if (code == '@')
20990075Sobrien	{
21090075Sobrien	  prefix = get_key_value (key);
21190075Sobrien	  if (prefix == 0)
21290075Sobrien	    prefix = std_prefix;
21390075Sobrien	}
21490075Sobrien      else
21590075Sobrien	prefix = getenv (key);
21650397Sobrien
21750397Sobrien      if (prefix == 0)
21890075Sobrien	prefix = PREFIX;
21990075Sobrien
22090075Sobrien      /* We used to strip trailing DIR_SEPARATORs here, but that can
22190075Sobrien	 sometimes yield a result with no separator when one was coded
22290075Sobrien	 and intended by the user, causing two path components to run
22390075Sobrien	 together.  */
22490075Sobrien
22590075Sobrien      old_name = name;
22690075Sobrien      name = concat (prefix, &name[keylen + 1], NULL);
22790075Sobrien      free (old_name);
22850397Sobrien    }
22950397Sobrien
23090075Sobrien  return name;
23190075Sobrien}
23250397Sobrien
23390075Sobrien/* In a NUL-terminated STRING, replace character C1 with C2 in-place.  */
23490075Sobrienstatic void
235132718Skantr (char *string, int c1, int c2)
23690075Sobrien{
23790075Sobrien  do
23850397Sobrien    {
23990075Sobrien      if (*string == c1)
24090075Sobrien	*string = c2;
24150397Sobrien    }
24290075Sobrien  while (*string++);
24350397Sobrien}
24450397Sobrien
245169689Skan/* Update PATH using KEY if PATH starts with PREFIX as a directory.
246169689Skan   The returned string is always malloc-ed, and the caller is
247169689Skan   responsible for freeing it.  */
24850397Sobrien
24990075Sobrienchar *
250132718Skanupdate_path (const char *path, const char *key)
25150397Sobrien{
252117395Skan  char *result, *p;
253169689Skan  const int len = strlen (std_prefix);
25490075Sobrien
255169689Skan  if (! strncmp (path, std_prefix, len)
256169689Skan      && (IS_DIR_SEPARATOR(path[len])
257169689Skan          || path[len] == '\0')
258169689Skan      && key != 0)
25950397Sobrien    {
26090075Sobrien      bool free_key = false;
26190075Sobrien
26250397Sobrien      if (key[0] != '$')
26390075Sobrien	{
26490075Sobrien	  key = concat ("@", key, NULL);
26590075Sobrien	  free_key = true;
26690075Sobrien	}
26750397Sobrien
268169689Skan      result = concat (key, &path[len], NULL);
26990075Sobrien      if (free_key)
27090075Sobrien	free ((char *) key);
27190075Sobrien      result = translate_name (result);
27250397Sobrien    }
27390075Sobrien  else
27490075Sobrien    result = xstrdup (path);
27552284Sobrien
276117395Skan#ifndef ALWAYS_STRIP_DOTDOT
277117395Skan#define ALWAYS_STRIP_DOTDOT 0
278117395Skan#endif
279117395Skan
280117395Skan  p = result;
281117395Skan  while (1)
282117395Skan    {
283117395Skan      char *src, *dest;
284117395Skan
285117395Skan      p = strchr (p, '.');
286117395Skan      if (p == NULL)
287117395Skan	break;
288117395Skan      /* Look for `/../'  */
289117395Skan      if (p[1] == '.'
290117395Skan	  && IS_DIR_SEPARATOR (p[2])
291117395Skan	  && (p != result && IS_DIR_SEPARATOR (p[-1])))
292117395Skan	{
293117395Skan	  *p = 0;
294117395Skan	  if (!ALWAYS_STRIP_DOTDOT && access (result, X_OK) == 0)
295117395Skan	    {
296117395Skan	      *p = '.';
297117395Skan	      break;
298117395Skan	    }
299117395Skan	  else
300117395Skan	    {
301117395Skan	      /* We can't access the dir, so we won't be able to
302117395Skan		 access dir/.. either.  Strip out `dir/../'.  If `dir'
303117395Skan		 turns out to be `.', strip one more path component.  */
304117395Skan	      dest = p;
305117395Skan	      do
306117395Skan		{
307117395Skan		  --dest;
308117395Skan		  while (dest != result && IS_DIR_SEPARATOR (*dest))
309117395Skan		    --dest;
310117395Skan		  while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
311117395Skan		    --dest;
312117395Skan		}
313117395Skan	      while (dest != result && *dest == '.');
314117395Skan	      /* If we have something like `./..' or `/..', don't
315117395Skan		 strip anything more.  */
316117395Skan	      if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
317117395Skan		{
318117395Skan		  *p = '.';
319117395Skan		  break;
320117395Skan		}
321117395Skan	      src = p + 3;
322117395Skan	      while (IS_DIR_SEPARATOR (*src))
323117395Skan		++src;
324117395Skan	      p = dest;
325117395Skan	      while ((*dest++ = *src++) != 0)
326117395Skan		;
327117395Skan	    }
328117395Skan	}
329117395Skan      else
330117395Skan	++p;
331117395Skan    }
332117395Skan
33390075Sobrien#ifdef UPDATE_PATH_HOST_CANONICALIZE
33490075Sobrien  /* Perform host dependent canonicalization when needed.  */
335117395Skan  UPDATE_PATH_HOST_CANONICALIZE (result);
33690075Sobrien#endif
33790075Sobrien
33852284Sobrien#ifdef DIR_SEPARATOR_2
33990075Sobrien  /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR.  */
34090075Sobrien  if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
34190075Sobrien    tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
34252284Sobrien#endif
34390075Sobrien
34452284Sobrien#if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
34550397Sobrien  if (DIR_SEPARATOR != '/')
34690075Sobrien    tr (result, '/', DIR_SEPARATOR);
34750397Sobrien#endif
34850397Sobrien
34990075Sobrien  return result;
35050397Sobrien}
35150397Sobrien
352132718Skan/* Reset the standard prefix.  */
35350397Sobrienvoid
354132718Skanset_std_prefix (const char *prefix, int len)
35550397Sobrien{
35650397Sobrien  std_prefix = save_string (prefix, len);
35750397Sobrien}
358