prefix.c revision 50397
190075Sobrien/* Utility to update paths from internal to external forms.
290075Sobrien   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
390075Sobrien
490075SobrienThis file is part of GNU CC.
590075Sobrien
690075SobrienGNU CC is free software; you can redistribute it and/or
790075Sobrienmodify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14Library General Public License for more details.
15
16You should have received a copy of the GNU Library General Public
17License along with GCC; see the file COPYING.  If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.  */
20
21/* This file contains routines to update a path, both to canonicalize
22   the directory format and to handle any prefix translation.
23
24   This file must be compiled with -DPREFIX= to specify the "prefix"
25   value used by configure.  If a filename does not begin with this
26   prefix, it will not be affected other than by directory canonicalization.
27
28   Each caller of 'update_path' may specify both a filename and
29   a translation prefix and consist of the name of the package that contains
30   the file ("@GCC", "@BINUTIL", "@GNU", etc).
31
32   If the prefix is not specified, the filename will only undergo
33   directory canonicalization.
34
35   If it is specified, the string given by PREFIX will be replaced
36   by the specified prefix (with a '@' in front unless the prefix begins
37   with a '$') and further translation will be done as follows
38   until none of the two conditions below are met:
39
40   1) If the filename begins with '@', the string between the '@' and
41   the end of the name or the first '/' or directory separator will
42   be considered a "key" and looked up as follows:
43
44   -- If this is a Win32 OS, then the Registry will be examined for
45      an entry of "key" in
46
47      HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\
48
49      if found, that value will be used.
50
51   -- If not found (or not a Win32 OS), the environment variable
52      key_ROOT (the value of "key" concatenated with the constant "_ROOT")
53      is tried.  If that fails, then PREFIX (see above) is used.
54
55   2) If the filename begins with a '$', the rest of the string up
56   to the end or the first '/' or directory separator will be used
57   as an environment variable, whose value will be returned.
58
59   Once all this is done, any '/' will be converted to DIR_SEPARATOR,
60   if they are different.
61
62   NOTE:  using resolve_keyed_path under Win32 requires linking with
63   advapi32.dll.  */
64
65
66#include "config.h"
67#ifdef __STDC__
68#include <stdarg.h>
69#else
70#include <varargs.h>
71#endif
72#include "system.h"
73#ifdef _WIN32
74#include <windows.h>
75#endif
76
77#include "gansidecl.h"
78
79static char *std_prefix = PREFIX;
80
81static char *get_key_value	PROTO((char *));
82static char *translate_name	PROTO((char *));
83static char *concat		PVPROTO((char *, ...));
84static char *save_string	PROTO((char *, int));
85
86#ifdef _WIN32
87static char *lookup_key		PROTO((char *));
88static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
89#endif
90
91/* Given KEY, as above, return its value.  */
92
93static char *
94get_key_value (key)
95     char *key;
96{
97  char *prefix = 0;
98  char *temp = 0;
99
100#ifdef _WIN32
101  prefix = lookup_key (key);
102#endif
103
104  if (prefix == 0)
105    prefix = getenv (temp = concat (key, "_ROOT", NULL_PTR));
106
107  if (prefix == 0)
108    prefix = std_prefix;
109
110  if (temp)
111    free (temp);
112
113  return prefix;
114}
115
116/* Concatenate a sequence of strings, returning the result.
117
118   This function is based on the one in libiberty.  */
119
120static char *
121concat VPROTO((char *first, ...))
122{
123  register int length;
124  register char *newstr;
125  register char *end;
126  register char *arg;
127  va_list args;
128#ifndef __STDC__
129  char *first;
130#endif
131
132  /* First compute the size of the result and get sufficient memory.  */
133
134  VA_START (args, first);
135#ifndef __STDC__
136  first = va_arg (args, char *);
137#endif
138
139  arg = first;
140  length = 0;
141
142  while (arg != 0)
143    {
144      length += strlen (arg);
145      arg = va_arg (args, char *);
146    }
147
148  newstr = (char *) malloc (length + 1);
149  va_end (args);
150
151  /* Now copy the individual pieces to the result string.  */
152
153  VA_START (args, first);
154#ifndef __STDC__
155  first = va_arg (args, char *);
156#endif
157
158  end = newstr;
159  arg = first;
160  while (arg != 0)
161    {
162      while (*arg)
163	*end++ = *arg++;
164      arg = va_arg (args, char *);
165    }
166  *end = '\000';
167  va_end (args);
168
169  return (newstr);
170}
171
172/* Return a copy of a string that has been placed in the heap.  */
173
174static char *
175save_string (s, len)
176     char *s;
177     int len;
178{
179  register char *result = (char *) malloc (len + 1);
180
181  bcopy (s, result, len);
182  result[len] = 0;
183  return result;
184}
185
186#ifdef _WIN32
187
188/* Look up "key" in the registry, as above.  */
189
190static char *
191lookup_key (key)
192     char *key;
193{
194  char *dst;
195  DWORD size;
196  DWORD type;
197  LONG res;
198
199  if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
200    {
201      res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
202			   KEY_READ, &reg_key);
203
204      if (res == ERROR_SUCCESS)
205	res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
206			     KEY_READ, &reg_key);
207
208      if (res != ERROR_SUCCESS)
209        {
210          reg_key = (HKEY) INVALID_HANDLE_VALUE;
211          return 0;
212        }
213    }
214
215  size = 32;
216  dst = (char *) malloc (size);
217
218  res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
219  if (res == ERROR_MORE_DATA && type == REG_SZ)
220    {
221      dst = (char *) realloc (dst, size);
222      res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
223    }
224
225  if (type != REG_SZ || res != ERROR_SUCCESS)
226    {
227      free (dst);
228      dst = 0;
229    }
230
231  return dst;
232}
233#endif
234
235/* If NAME starts with a '@' or '$', apply the translation rules above
236   and return a new name.  Otherwise, return the given name.  */
237
238static char *
239translate_name (name)
240     char *name;
241{
242  char code = name[0];
243  char *key, *prefix = 0;
244  int keylen;
245
246  if (code != '@' && code != '$')
247    return name;
248
249  for (keylen = 0;
250       (name[keylen + 1] != 0 && name[keylen + 1] != '/'
251#ifdef DIR_SEPARATOR
252	&& name[keylen + 1] != DIR_SEPARATOR
253#endif
254	);
255       keylen++)
256    ;
257
258  key = alloca (keylen + 1);
259  strncpy (key, &name[1], keylen);
260  key[keylen] = 0;
261
262  name = &name[keylen + 1];
263
264  if (code == '@')
265    {
266      prefix = get_key_value (key);
267      if (prefix == 0)
268	prefix = std_prefix;
269    }
270  else
271    prefix = getenv (key);
272
273  if (prefix == 0)
274    prefix = PREFIX;
275
276  /* Remove any trailing directory separator from what we got.  */
277  if (prefix[strlen (prefix) - 1] == '/'
278#ifdef DIR_SEPARATOR
279      || prefix[strlen (prefix) - 1] == DIR_SEPARATOR
280#endif
281      )
282    {
283      prefix = save_string (prefix, strlen (prefix));
284      prefix[strlen (prefix) - 1] = 0;
285    }
286
287  return concat (prefix, name, NULL_PTR);
288}
289
290/* Update PATH using KEY if PATH starts with PREFIX.  */
291
292char *
293update_path (path, key)
294     char *path;
295     char *key;
296{
297  if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
298    {
299      if (key[0] != '$')
300	key = concat ("@", key, NULL_PTR);
301
302      path = concat (key, &path[strlen (std_prefix)], NULL_PTR);
303
304      while (path[0] == '@' || path[0] == '$')
305	path = translate_name (path);
306    }
307
308#ifdef DIR_SEPARATOR
309  if (DIR_SEPARATOR != '/')
310    {
311      int i;
312      int len = strlen (path);
313
314      path = save_string (path, len);
315      for (i = 0; i < len; i++)
316	if (path[i] == '/')
317	  path[i] = DIR_SEPARATOR;
318    }
319#endif
320
321  return path;
322}
323
324/* Reset the standard prefix */
325void
326set_std_prefix (prefix, len)
327     char *prefix;
328     int len;
329{
330  std_prefix = save_string (prefix, len);
331}
332