OSDN Git Service

* Check in merge from gcc2. See ChangeLog.11 and ChangeLog.12
[pf3gnuchains/gcc-fork.git] / gcc / prefix.c
1 /* Utility to update paths from internal to external forms.
2    Copyright (C) 1997, 1998 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with GCC; see the file COPYING.  If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, 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
79 static char *std_prefix = PREFIX;
80
81 static char *get_key_value      PROTO((char *));
82 static char *translate_name     PROTO((char *));
83 static char *concat             PVPROTO((char *, ...));
84 static char *save_string        PROTO((char *, int));
85
86 #ifdef _WIN32
87 static char *lookup_key         PROTO((char *));
88 static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
89 #endif
90
91 /* Given KEY, as above, return its value.  */
92
93 static char *
94 get_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
120 static char *
121 concat 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
174 static char *
175 save_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
190 static char *
191 lookup_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
238 static char *
239 translate_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
292 char *
293 update_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 */
325 void
326 set_std_prefix (prefix, len)
327      char *prefix;
328      int len;
329 {
330   std_prefix = save_string (prefix, len);
331 }