]>
Commit | Line | Data |
---|---|---|
4a5121b5 | 1 | /* Utility to update paths from internal to external forms. |
9311a396 | 2 | Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. |
4a5121b5 JL |
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 | ||
f4ab28e3 | 47 | HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY> |
4a5121b5 | 48 | |
f4ab28e3 MK |
49 | if found, that value will be used. <KEY> defaults to GCC version |
50 | string, but can be overridden at configuration time. | |
4a5121b5 JL |
51 | |
52 | -- If not found (or not a Win32 OS), the environment variable | |
53 | key_ROOT (the value of "key" concatenated with the constant "_ROOT") | |
54 | is tried. If that fails, then PREFIX (see above) is used. | |
55 | ||
56 | 2) If the filename begins with a '$', the rest of the string up | |
57 | to the end or the first '/' or directory separator will be used | |
58 | as an environment variable, whose value will be returned. | |
59 | ||
60 | Once all this is done, any '/' will be converted to DIR_SEPARATOR, | |
61 | if they are different. | |
62 | ||
63 | NOTE: using resolve_keyed_path under Win32 requires linking with | |
64 | advapi32.dll. */ | |
65 | ||
66 | ||
67 | #include "config.h" | |
670ee920 | 68 | #include "system.h" |
f4ab28e3 | 69 | #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) |
4a5121b5 JL |
70 | #include <windows.h> |
71 | #endif | |
460ee112 | 72 | #include "prefix.h" |
4a5121b5 | 73 | |
460ee112 | 74 | static const char *std_prefix = PREFIX; |
6ed4bb9a | 75 | |
13536812 KG |
76 | static const char *get_key_value PARAMS ((char *)); |
77 | static const char *translate_name PARAMS ((const char *)); | |
78 | static char *save_string PARAMS ((const char *, int)); | |
4a5121b5 | 79 | |
f4ab28e3 | 80 | #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) |
13536812 | 81 | static char *lookup_key PARAMS ((char *)); |
4a5121b5 JL |
82 | static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE; |
83 | #endif | |
84 | ||
4a5121b5 JL |
85 | /* Given KEY, as above, return its value. */ |
86 | ||
460ee112 | 87 | static const char * |
4a5121b5 JL |
88 | get_key_value (key) |
89 | char *key; | |
90 | { | |
460ee112 | 91 | const char *prefix = 0; |
6ed4bb9a | 92 | char *temp = 0; |
4a5121b5 | 93 | |
f4ab28e3 | 94 | #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) |
4a5121b5 JL |
95 | prefix = lookup_key (key); |
96 | #endif | |
97 | ||
98 | if (prefix == 0) | |
6ed4bb9a | 99 | prefix = getenv (temp = concat (key, "_ROOT", NULL_PTR)); |
4a5121b5 JL |
100 | |
101 | if (prefix == 0) | |
6ed4bb9a MM |
102 | prefix = std_prefix; |
103 | ||
104 | if (temp) | |
105 | free (temp); | |
4a5121b5 JL |
106 | |
107 | return prefix; | |
108 | } | |
109 | ||
110 | /* Concatenate a sequence of strings, returning the result. | |
111 | ||
112 | This function is based on the one in libiberty. */ | |
113 | ||
2778b98d | 114 | char * |
13536812 | 115 | concat VPARAMS ((const char *first, ...)) |
4a5121b5 JL |
116 | { |
117 | register int length; | |
118 | register char *newstr; | |
119 | register char *end; | |
2778b98d | 120 | register const char *arg; |
4a5121b5 | 121 | va_list args; |
5148a72b | 122 | #ifndef ANSI_PROTOTYPES |
2778b98d | 123 | const char *first; |
4a5121b5 JL |
124 | #endif |
125 | ||
126 | /* First compute the size of the result and get sufficient memory. */ | |
127 | ||
128 | VA_START (args, first); | |
5148a72b | 129 | #ifndef ANSI_PROTOTYPES |
2778b98d | 130 | first = va_arg (args, const char *); |
4a5121b5 JL |
131 | #endif |
132 | ||
133 | arg = first; | |
134 | length = 0; | |
135 | ||
136 | while (arg != 0) | |
137 | { | |
138 | length += strlen (arg); | |
2778b98d | 139 | arg = va_arg (args, const char *); |
4a5121b5 JL |
140 | } |
141 | ||
3ea6b476 | 142 | newstr = (char *) xmalloc (length + 1); |
4a5121b5 JL |
143 | va_end (args); |
144 | ||
145 | /* Now copy the individual pieces to the result string. */ | |
146 | ||
147 | VA_START (args, first); | |
5148a72b | 148 | #ifndef ANSI_PROTOTYPES |
4a5121b5 JL |
149 | first = va_arg (args, char *); |
150 | #endif | |
151 | ||
152 | end = newstr; | |
153 | arg = first; | |
154 | while (arg != 0) | |
155 | { | |
156 | while (*arg) | |
157 | *end++ = *arg++; | |
2778b98d | 158 | arg = va_arg (args, const char *); |
4a5121b5 JL |
159 | } |
160 | *end = '\000'; | |
161 | va_end (args); | |
162 | ||
163 | return (newstr); | |
164 | } | |
165 | ||
166 | /* Return a copy of a string that has been placed in the heap. */ | |
167 | ||
168 | static char * | |
169 | save_string (s, len) | |
460ee112 KG |
170 | const char *s; |
171 | int len; | |
4a5121b5 | 172 | { |
460ee112 | 173 | register char *result = xmalloc (len + 1); |
4a5121b5 JL |
174 | |
175 | bcopy (s, result, len); | |
176 | result[len] = 0; | |
177 | return result; | |
178 | } | |
179 | ||
f4ab28e3 | 180 | #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY) |
4a5121b5 JL |
181 | |
182 | /* Look up "key" in the registry, as above. */ | |
183 | ||
184 | static char * | |
185 | lookup_key (key) | |
186 | char *key; | |
187 | { | |
188 | char *dst; | |
189 | DWORD size; | |
190 | DWORD type; | |
191 | LONG res; | |
192 | ||
193 | if (reg_key == (HKEY) INVALID_HANDLE_VALUE) | |
194 | { | |
195 | res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, | |
196 | KEY_READ, ®_key); | |
197 | ||
198 | if (res == ERROR_SUCCESS) | |
199 | res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0, | |
200 | KEY_READ, ®_key); | |
201 | ||
f4ab28e3 MK |
202 | if (res == ERROR_SUCCESS) |
203 | res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0, | |
204 | KEY_READ, ®_key); | |
205 | ||
4a5121b5 JL |
206 | if (res != ERROR_SUCCESS) |
207 | { | |
208 | reg_key = (HKEY) INVALID_HANDLE_VALUE; | |
209 | return 0; | |
210 | } | |
211 | } | |
212 | ||
213 | size = 32; | |
3ea6b476 | 214 | dst = (char *) xmalloc (size); |
4a5121b5 JL |
215 | |
216 | res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size); | |
217 | if (res == ERROR_MORE_DATA && type == REG_SZ) | |
218 | { | |
3ea6b476 | 219 | dst = (char *) xrealloc (dst, size); |
4a5121b5 JL |
220 | res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size); |
221 | } | |
222 | ||
223 | if (type != REG_SZ || res != ERROR_SUCCESS) | |
224 | { | |
225 | free (dst); | |
226 | dst = 0; | |
227 | } | |
228 | ||
229 | return dst; | |
230 | } | |
231 | #endif | |
232 | ||
233 | /* If NAME starts with a '@' or '$', apply the translation rules above | |
234 | and return a new name. Otherwise, return the given name. */ | |
235 | ||
460ee112 | 236 | static const char * |
4a5121b5 | 237 | translate_name (name) |
460ee112 | 238 | const char *name; |
4a5121b5 JL |
239 | { |
240 | char code = name[0]; | |
460ee112 KG |
241 | char *key; |
242 | const char *prefix = 0; | |
4a5121b5 JL |
243 | int keylen; |
244 | ||
245 | if (code != '@' && code != '$') | |
246 | return name; | |
247 | ||
248 | for (keylen = 0; | |
509781a4 | 249 | (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1])); |
4a5121b5 JL |
250 | keylen++) |
251 | ; | |
252 | ||
804a4e13 | 253 | key = (char *) alloca (keylen + 1); |
4a5121b5 JL |
254 | strncpy (key, &name[1], keylen); |
255 | key[keylen] = 0; | |
256 | ||
257 | name = &name[keylen + 1]; | |
258 | ||
259 | if (code == '@') | |
260 | { | |
261 | prefix = get_key_value (key); | |
262 | if (prefix == 0) | |
6ed4bb9a | 263 | prefix = std_prefix; |
4a5121b5 JL |
264 | } |
265 | else | |
e5e809f4 JL |
266 | prefix = getenv (key); |
267 | ||
268 | if (prefix == 0) | |
269 | prefix = PREFIX; | |
4a5121b5 | 270 | |
7146dfdd HB |
271 | /* Remove any trailing directory separator from what we got. First check |
272 | for an empty prefix. */ | |
273 | if (prefix[0] && IS_DIR_SEPARATOR (prefix[strlen (prefix) - 1])) | |
4a5121b5 | 274 | { |
ad85216e | 275 | char * temp = xstrdup (prefix); |
460ee112 KG |
276 | temp[strlen (temp) - 1] = 0; |
277 | prefix = temp; | |
4a5121b5 JL |
278 | } |
279 | ||
280 | return concat (prefix, name, NULL_PTR); | |
281 | } | |
282 | ||
283 | /* Update PATH using KEY if PATH starts with PREFIX. */ | |
284 | ||
460ee112 | 285 | const char * |
4a5121b5 | 286 | update_path (path, key) |
460ee112 KG |
287 | const char *path; |
288 | const char *key; | |
4a5121b5 | 289 | { |
6ed4bb9a | 290 | if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0) |
4a5121b5 JL |
291 | { |
292 | if (key[0] != '$') | |
293 | key = concat ("@", key, NULL_PTR); | |
294 | ||
6ed4bb9a | 295 | path = concat (key, &path[strlen (std_prefix)], NULL_PTR); |
4a5121b5 JL |
296 | |
297 | while (path[0] == '@' || path[0] == '$') | |
298 | path = translate_name (path); | |
299 | } | |
509781a4 ME |
300 | |
301 | #ifdef DIR_SEPARATOR_2 | |
302 | /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */ | |
303 | if (DIR_SEPARATOR != DIR_SEPARATOR_2) | |
304 | { | |
ad85216e | 305 | char *new_path = xstrdup (path); |
509781a4 | 306 | path = new_path; |
ad85216e KG |
307 | do { |
308 | if (*new_path == DIR_SEPARATOR_2) | |
309 | *new_path = DIR_SEPARATOR; | |
310 | } while (*new_path++); | |
509781a4 ME |
311 | } |
312 | #endif | |
4a5121b5 | 313 | |
509781a4 | 314 | #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2) |
4a5121b5 JL |
315 | if (DIR_SEPARATOR != '/') |
316 | { | |
ad85216e | 317 | char *new_path = xstrdup (path); |
509781a4 | 318 | path = new_path; |
ad85216e KG |
319 | do { |
320 | if (*new_path == '/') | |
321 | *new_path = DIR_SEPARATOR; | |
fbb740da | 322 | } while (*new_path++); |
4a5121b5 JL |
323 | } |
324 | #endif | |
325 | ||
326 | return path; | |
327 | } | |
6ed4bb9a MM |
328 | |
329 | /* Reset the standard prefix */ | |
330 | void | |
331 | set_std_prefix (prefix, len) | |
460ee112 KG |
332 | const char *prefix; |
333 | int len; | |
6ed4bb9a MM |
334 | { |
335 | std_prefix = save_string (prefix, len); | |
336 | } |