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