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