]>
Commit | Line | Data |
---|---|---|
8603f9c5 | 1 | /* Handle CLASSPATH, -classpath, and path searching. |
f309ff0a SB |
2 | Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 |
3 | Free Software Foundation, Inc. | |
8603f9c5 | 4 | |
f309ff0a | 5 | This file is part of GCC. |
8603f9c5 | 6 | |
f309ff0a | 7 | GCC is free software; you can redistribute it and/or modify |
8603f9c5 TT |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
f309ff0a | 12 | GCC is distributed in the hope that it will be useful, |
8603f9c5 TT |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
f309ff0a | 18 | along with GCC; see the file COPYING. If not, write to |
8603f9c5 TT |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. | |
21 | ||
22 | Java and all Java-based marks are trademarks or registered trademarks | |
23 | of Sun Microsystems, Inc. in the United States and other countries. | |
24 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
25 | ||
26 | /* Written by Tom Tromey <tromey@cygnus.com>, October 1998. */ | |
27 | ||
4504ead1 | 28 | #include "config.h" |
8603f9c5 | 29 | #include "system.h" |
4977bab6 ZW |
30 | #include "coretypes.h" |
31 | #include "tm.h" | |
8603f9c5 | 32 | |
9fef1fe3 AG |
33 | #include <dirent.h> |
34 | ||
8603f9c5 TT |
35 | #include "jcf.h" |
36 | ||
71651d6c TT |
37 | #ifndef DIR_UP |
38 | #define DIR_UP ".." | |
39 | #endif | |
40 | ||
8603f9c5 TT |
41 | \f |
42 | ||
43 | /* Possible flag values. */ | |
44 | #define FLAG_SYSTEM 1 | |
45 | #define FLAG_ZIP 2 | |
46 | ||
47 | /* We keep linked lists of directory names. A ``directory'' can be | |
48 | either an ordinary directory or a .zip file. */ | |
49 | struct entry | |
50 | { | |
51 | char *name; | |
52 | int flags; | |
53 | struct entry *next; | |
54 | }; | |
55 | ||
d2097937 KG |
56 | static void free_entry (struct entry **); |
57 | static void append_entry (struct entry **, struct entry *); | |
58 | static void add_entry (struct entry **, const char *, int); | |
59 | static void add_path (struct entry **, const char *, int); | |
c8e7d2e6 | 60 | |
8603f9c5 TT |
61 | /* We support several different ways to set the class path. |
62 | ||
f34ff6d6 | 63 | built-in system directory (only libgcj.jar) |
8603f9c5 | 64 | CLASSPATH environment variable |
db444fbe | 65 | -classpath option overrides $CLASSPATH |
2a85660d PB |
66 | -CLASSPATH option is a synonym for -classpath (for compatibility) |
67 | -bootclasspath overrides built-in | |
9fef1fe3 | 68 | -extdirs sets the extensions directory path (overrides built-in) |
8603f9c5 TT |
69 | -I prepends path to list |
70 | ||
71 | We implement this by keeping several path lists, and then simply | |
72 | ignoring the ones which are not relevant. */ | |
73 | ||
74 | /* This holds all the -I directories. */ | |
75 | static struct entry *include_dirs; | |
76 | ||
77 | /* This holds the CLASSPATH environment variable. */ | |
78 | static struct entry *classpath_env; | |
79 | ||
db444fbe | 80 | /* This holds the -classpath command-line option. */ |
2a85660d | 81 | static struct entry *classpath_user; |
8603f9c5 TT |
82 | |
83 | /* This holds the default directories. Some of these will have the | |
84 | "system" flag set. */ | |
85 | static struct entry *sys_dirs; | |
86 | ||
9fef1fe3 AG |
87 | /* This holds the extensions path entries. */ |
88 | static struct entry *extensions; | |
89 | ||
8603f9c5 TT |
90 | /* This is the sealed list. It is just a combination of other lists. */ |
91 | static struct entry *sealed; | |
92 | ||
93 | /* We keep track of the longest path we've seen. */ | |
94 | static int longest_path = 0; | |
95 | ||
96 | \f | |
97 | ||
98 | static void | |
0a2f0c54 | 99 | free_entry (struct entry **entp) |
8603f9c5 TT |
100 | { |
101 | struct entry *e, *n; | |
102 | ||
103 | for (e = *entp; e; e = n) | |
104 | { | |
105 | n = e->next; | |
106 | free (e->name); | |
107 | free (e); | |
108 | } | |
109 | *entp = NULL; | |
110 | } | |
111 | ||
112 | static void | |
0a2f0c54 | 113 | append_entry (struct entry **entp, struct entry *ent) |
8603f9c5 TT |
114 | { |
115 | /* It doesn't matter if this is slow, since it is run only at | |
116 | startup, and then infrequently. */ | |
117 | struct entry *e; | |
118 | ||
119 | /* Find end of list. */ | |
120 | for (e = *entp; e && e->next; e = e->next) | |
121 | ; | |
122 | ||
123 | if (e) | |
124 | e->next = ent; | |
125 | else | |
126 | *entp = ent; | |
127 | } | |
128 | ||
129 | static void | |
0a2f0c54 | 130 | add_entry (struct entry **entp, const char *filename, int is_system) |
8603f9c5 TT |
131 | { |
132 | int len; | |
133 | struct entry *n; | |
134 | ||
a92cb0c3 | 135 | n = ALLOC (sizeof (struct entry)); |
8603f9c5 TT |
136 | n->flags = is_system ? FLAG_SYSTEM : 0; |
137 | n->next = NULL; | |
138 | ||
139 | len = strlen (filename); | |
530d4230 | 140 | |
3dce1408 ZW |
141 | if (len > 4 && (FILENAME_CMP (filename + len - 4, ".zip") == 0 |
142 | || FILENAME_CMP (filename + len - 4, ".jar") == 0)) | |
8603f9c5 TT |
143 | { |
144 | n->flags |= FLAG_ZIP; | |
145 | /* If the user uses -classpath then he'll have to include | |
f34ff6d6 | 146 | libgcj.jar in the value. We check for this in a simplistic |
8603f9c5 TT |
147 | way. Symlinks will fool this test. This is only used for |
148 | -MM and -MMD, so it probably isn't terribly important. */ | |
3dce1408 | 149 | if (! FILENAME_CMP (filename, LIBGCJ_ZIP_FILE)) |
8603f9c5 TT |
150 | n->flags |= FLAG_SYSTEM; |
151 | } | |
152 | ||
733b3a87 TT |
153 | /* Note that we add a trailing separator to `.zip' names as well. |
154 | This is a little hack that lets the searching code in jcf-io.c | |
155 | work more easily. Eww. */ | |
530d4230 | 156 | if (! IS_DIR_SEPARATOR (filename[len - 1])) |
8603f9c5 | 157 | { |
a92cb0c3 | 158 | char *f2 = alloca (len + 2); |
8603f9c5 TT |
159 | strcpy (f2, filename); |
160 | f2[len] = DIR_SEPARATOR; | |
161 | f2[len + 1] = '\0'; | |
c2e3db92 | 162 | n->name = xstrdup (f2); |
8603f9c5 TT |
163 | ++len; |
164 | } | |
165 | else | |
c2e3db92 | 166 | n->name = xstrdup (filename); |
8603f9c5 TT |
167 | |
168 | if (len > longest_path) | |
169 | longest_path = len; | |
170 | ||
171 | append_entry (entp, n); | |
172 | } | |
173 | ||
174 | static void | |
0a2f0c54 | 175 | add_path (struct entry **entp, const char *cp, int is_system) |
8603f9c5 | 176 | { |
c8e7d2e6 | 177 | const char *startp, *endp; |
8603f9c5 TT |
178 | |
179 | if (cp) | |
180 | { | |
a92cb0c3 | 181 | char *buf = alloca (strlen (cp) + 3); |
8603f9c5 TT |
182 | startp = endp = cp; |
183 | while (1) | |
184 | { | |
185 | if (! *endp || *endp == PATH_SEPARATOR) | |
186 | { | |
8603f9c5 TT |
187 | if (endp == startp) |
188 | { | |
189 | buf[0] = '.'; | |
190 | buf[1] = DIR_SEPARATOR; | |
191 | buf[2] = '\0'; | |
192 | } | |
71f6a8e2 | 193 | else |
8603f9c5 | 194 | { |
71f6a8e2 TT |
195 | strncpy (buf, startp, endp - startp); |
196 | buf[endp - startp] = '\0'; | |
8603f9c5 | 197 | } |
8603f9c5 TT |
198 | add_entry (entp, buf, is_system); |
199 | if (! *endp) | |
200 | break; | |
201 | ++endp; | |
202 | startp = endp; | |
203 | } | |
204 | else | |
205 | ++endp; | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
2a85660d PB |
210 | static int init_done = 0; |
211 | ||
8603f9c5 TT |
212 | /* Initialize the path module. */ |
213 | void | |
0a2f0c54 | 214 | jcf_path_init (void) |
8603f9c5 TT |
215 | { |
216 | char *cp; | |
71651d6c TT |
217 | char *try, sep[2]; |
218 | struct stat stat_b; | |
219 | int found = 0, len; | |
8603f9c5 | 220 | |
2a85660d PB |
221 | if (init_done) |
222 | return; | |
223 | init_done = 1; | |
71651d6c TT |
224 | |
225 | sep[0] = DIR_SEPARATOR; | |
226 | sep[1] = '\0'; | |
227 | ||
2f8dd115 | 228 | GET_ENVIRONMENT (cp, "GCC_EXEC_PREFIX"); |
71651d6c TT |
229 | if (cp) |
230 | { | |
231 | try = alloca (strlen (cp) + 50); | |
232 | /* The exec prefix can be something like | |
233 | /usr/local/bin/../lib/gcc-lib/. We want to change this | |
9fef1fe3 | 234 | into a pointer to the share/java directory. We support two |
71651d6c TT |
235 | configurations: one where prefix and exec-prefix are the |
236 | same, and one where exec-prefix is `prefix/SOMETHING'. */ | |
237 | strcpy (try, cp); | |
238 | strcat (try, DIR_UP); | |
239 | strcat (try, sep); | |
240 | strcat (try, DIR_UP); | |
241 | strcat (try, sep); | |
242 | len = strlen (try); | |
243 | ||
244 | strcpy (try + len, "share"); | |
245 | strcat (try, sep); | |
9fef1fe3 AG |
246 | strcat (try, "java"); |
247 | strcat (try, sep); | |
248 | strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar"); | |
71651d6c TT |
249 | if (! stat (try, &stat_b)) |
250 | { | |
251 | add_entry (&sys_dirs, try, 1); | |
252 | found = 1; | |
9fef1fe3 AG |
253 | strcpy (&try[strlen (try) |
254 | - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")], | |
255 | sep); | |
256 | strcat (try, "ext"); | |
257 | strcat (try, sep); | |
258 | if (! stat (try, &stat_b)) | |
259 | jcf_path_extdirs_arg (try); | |
71651d6c TT |
260 | } |
261 | else | |
262 | { | |
263 | strcpy (try + len, DIR_UP); | |
264 | strcat (try, sep); | |
265 | strcat (try, "share"); | |
266 | strcat (try, sep); | |
9fef1fe3 AG |
267 | strcat (try, "java"); |
268 | strcat (try, sep); | |
269 | strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar"); | |
71651d6c TT |
270 | if (! stat (try, &stat_b)) |
271 | { | |
272 | add_entry (&sys_dirs, try, 1); | |
273 | found = 1; | |
9fef1fe3 AG |
274 | strcpy (&try[strlen (try) |
275 | - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")], | |
276 | sep); | |
277 | strcat (try, "ext"); | |
278 | strcat (try, sep); | |
279 | if (! stat (try, &stat_b)) | |
280 | jcf_path_extdirs_arg (try); | |
71651d6c TT |
281 | } |
282 | } | |
283 | } | |
284 | if (! found) | |
285 | { | |
286 | /* Desperation: use the installed one. */ | |
9fef1fe3 | 287 | char *extdirs; |
71651d6c | 288 | add_entry (&sys_dirs, LIBGCJ_ZIP_FILE, 1); |
a92cb0c3 | 289 | extdirs = alloca (strlen (LIBGCJ_ZIP_FILE) + 1); |
9fef1fe3 AG |
290 | strcpy (extdirs, LIBGCJ_ZIP_FILE); |
291 | strcpy (&extdirs[strlen (LIBGCJ_ZIP_FILE) | |
292 | - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")], | |
293 | "ext"); | |
294 | strcat (extdirs, sep); | |
295 | if (! stat (extdirs, &stat_b)) | |
296 | jcf_path_extdirs_arg (extdirs); | |
71651d6c | 297 | } |
8603f9c5 | 298 | |
2f8dd115 | 299 | GET_ENVIRONMENT (cp, "CLASSPATH"); |
8603f9c5 TT |
300 | add_path (&classpath_env, cp, 0); |
301 | } | |
302 | ||
2a85660d PB |
303 | /* Call this when -classpath is seen on the command line. |
304 | This overrides only the $CLASSPATH environment variable. | |
db444fbe | 305 | */ |
8603f9c5 | 306 | void |
0a2f0c54 | 307 | jcf_path_classpath_arg (const char *path) |
8603f9c5 | 308 | { |
2a85660d PB |
309 | free_entry (&classpath_user); |
310 | add_path (&classpath_user, path, 0); | |
8603f9c5 TT |
311 | } |
312 | ||
2a85660d | 313 | /* Call this when -bootclasspath is seen on the command line. |
db444fbe | 314 | */ |
8603f9c5 | 315 | void |
0a2f0c54 | 316 | jcf_path_bootclasspath_arg (const char *path) |
8603f9c5 | 317 | { |
2a85660d PB |
318 | free_entry (&sys_dirs); |
319 | add_path (&sys_dirs, path, 1); | |
8603f9c5 TT |
320 | } |
321 | ||
9fef1fe3 AG |
322 | /* Call this when -extdirs is seen on the command line. |
323 | */ | |
324 | void | |
0a2f0c54 | 325 | jcf_path_extdirs_arg (const char *cp) |
9fef1fe3 AG |
326 | { |
327 | const char *startp, *endp; | |
328 | ||
329 | free_entry (&extensions); | |
330 | ||
331 | if (cp) | |
332 | { | |
a92cb0c3 | 333 | char *buf = alloca (strlen (cp) + 3); |
9fef1fe3 AG |
334 | startp = endp = cp; |
335 | while (1) | |
336 | { | |
337 | if (! *endp || *endp == PATH_SEPARATOR) | |
338 | { | |
339 | if (endp == startp) | |
340 | return; | |
341 | ||
342 | strncpy (buf, startp, endp - startp); | |
343 | buf[endp - startp] = '\0'; | |
344 | ||
345 | { | |
346 | DIR *dirp = NULL; | |
347 | int dirname_length = strlen (buf); | |
348 | ||
349 | dirp = opendir (buf); | |
350 | if (dirp == NULL) | |
351 | return; | |
352 | ||
353 | for (;;) | |
354 | { | |
355 | struct dirent *direntp = readdir (dirp); | |
356 | ||
357 | if (!direntp) | |
358 | break; | |
359 | ||
360 | if (direntp->d_name[0] != '.') | |
361 | { | |
a92cb0c3 JMH |
362 | char *name = alloca (dirname_length |
363 | + strlen (direntp->d_name) + 2); | |
9fef1fe3 | 364 | strcpy (name, buf); |
530d4230 | 365 | if (! IS_DIR_SEPARATOR (name[dirname_length-1])) |
9fef1fe3 AG |
366 | { |
367 | name[dirname_length] = DIR_SEPARATOR; | |
368 | name[dirname_length+1] = 0; | |
369 | } | |
370 | strcat (name, direntp->d_name); | |
371 | add_entry (&extensions, name, 0); | |
372 | } | |
373 | } | |
f6e9619a MM |
374 | if (dirp) |
375 | closedir (dirp); | |
9fef1fe3 AG |
376 | } |
377 | ||
378 | if (! *endp) | |
379 | break; | |
380 | ++endp; | |
381 | startp = endp; | |
382 | } | |
383 | else | |
384 | ++endp; | |
385 | } | |
386 | } | |
387 | } | |
388 | ||
8603f9c5 TT |
389 | /* Call this when -I is seen on the command line. */ |
390 | void | |
0a2f0c54 | 391 | jcf_path_include_arg (const char *path) |
8603f9c5 TT |
392 | { |
393 | add_entry (&include_dirs, path, 0); | |
394 | } | |
395 | ||
396 | /* We `seal' the path by linking everything into one big list. Then | |
4266d0b2 TT |
397 | we provide a way to iterate through the sealed list. If PRINT is |
398 | true then we print the final class path to stderr. */ | |
8603f9c5 | 399 | void |
0a2f0c54 | 400 | jcf_path_seal (int print) |
8603f9c5 | 401 | { |
8603f9c5 TT |
402 | struct entry *secondary; |
403 | ||
404 | sealed = include_dirs; | |
405 | include_dirs = NULL; | |
406 | ||
2a85660d | 407 | if (classpath_user) |
8603f9c5 | 408 | { |
2a85660d PB |
409 | secondary = classpath_user; |
410 | classpath_user = NULL; | |
8603f9c5 TT |
411 | } |
412 | else | |
413 | { | |
2a85660d PB |
414 | if (! classpath_env) |
415 | add_entry (&classpath_env, ".", 0); | |
416 | ||
8603f9c5 TT |
417 | secondary = classpath_env; |
418 | classpath_env = NULL; | |
419 | } | |
420 | ||
2a85660d PB |
421 | |
422 | free_entry (&classpath_user); | |
8603f9c5 TT |
423 | free_entry (&classpath_env); |
424 | ||
425 | append_entry (&sealed, secondary); | |
2a85660d | 426 | append_entry (&sealed, sys_dirs); |
9fef1fe3 | 427 | append_entry (&sealed, extensions); |
2a85660d | 428 | sys_dirs = NULL; |
9fef1fe3 | 429 | extensions = NULL; |
4266d0b2 TT |
430 | |
431 | if (print) | |
432 | { | |
433 | struct entry *ent; | |
434 | fprintf (stderr, "Class path starts here:\n"); | |
435 | for (ent = sealed; ent; ent = ent->next) | |
436 | { | |
437 | fprintf (stderr, " %s", ent->name); | |
438 | if ((ent->flags & FLAG_SYSTEM)) | |
439 | fprintf (stderr, " (system)"); | |
440 | if ((ent->flags & FLAG_ZIP)) | |
441 | fprintf (stderr, " (zip)"); | |
442 | fprintf (stderr, "\n"); | |
443 | } | |
444 | } | |
8603f9c5 TT |
445 | } |
446 | ||
447 | void * | |
0a2f0c54 | 448 | jcf_path_start (void) |
8603f9c5 TT |
449 | { |
450 | return (void *) sealed; | |
451 | } | |
452 | ||
453 | void * | |
0a2f0c54 | 454 | jcf_path_next (void *x) |
8603f9c5 TT |
455 | { |
456 | struct entry *ent = (struct entry *) x; | |
457 | return (void *) ent->next; | |
458 | } | |
459 | ||
460 | /* We guarantee that the return path will either be a zip file, or it | |
461 | will end with a directory separator. */ | |
462 | char * | |
0a2f0c54 | 463 | jcf_path_name (void *x) |
8603f9c5 TT |
464 | { |
465 | struct entry *ent = (struct entry *) x; | |
466 | return ent->name; | |
467 | } | |
468 | ||
469 | int | |
0a2f0c54 | 470 | jcf_path_is_zipfile (void *x) |
8603f9c5 TT |
471 | { |
472 | struct entry *ent = (struct entry *) x; | |
473 | return (ent->flags & FLAG_ZIP); | |
474 | } | |
475 | ||
476 | int | |
0a2f0c54 | 477 | jcf_path_is_system (void *x) |
8603f9c5 TT |
478 | { |
479 | struct entry *ent = (struct entry *) x; | |
480 | return (ent->flags & FLAG_SYSTEM); | |
481 | } | |
482 | ||
483 | int | |
0a2f0c54 | 484 | jcf_path_max_len (void) |
8603f9c5 TT |
485 | { |
486 | return longest_path; | |
487 | } |