OSDN Git Service

* ChangeLog: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-path.c
1 /* Handle CLASSPATH, -classpath, and path searching.
2
3    Copyright (C) 1998, 1999, 2000, 2001, 2002  Free Software Foundation, Inc.
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
26 #include "config.h"
27 #include "system.h"
28
29 #include <dirent.h>
30
31 #include "jcf.h"
32
33 /* By default, colon separates directories in a path.  */
34 #ifndef PATH_SEPARATOR
35 #define PATH_SEPARATOR ':'
36 #endif
37
38 #ifndef DIR_SEPARATOR
39 #define DIR_SEPARATOR '/'
40 #endif
41
42 #ifndef DIR_UP
43 #define DIR_UP ".."
44 #endif
45
46 \f
47
48 /* Possible flag values.  */
49 #define FLAG_SYSTEM 1
50 #define FLAG_ZIP    2
51
52 /* We keep linked lists of directory names.  A ``directory'' can be
53    either an ordinary directory or a .zip file.  */
54 struct entry
55 {
56   char *name;
57   int flags;
58   struct entry *next;
59 };
60
61 static void free_entry PARAMS ((struct entry **));
62 static void append_entry PARAMS ((struct entry **, struct entry *));
63 static void add_entry PARAMS ((struct entry **, const char *, int));
64 static void add_path PARAMS ((struct entry **, const char *, int));
65
66 /* We support several different ways to set the class path.
67
68    built-in system directory (only libgcj.jar)
69    CLASSPATH environment variable
70    -classpath option overrides $CLASSPATH
71    -CLASSPATH option is a synonym for -classpath (for compatibility)
72    -bootclasspath overrides built-in
73    -extdirs sets the extensions directory path (overrides built-in)
74    -I prepends path to list
75
76    We implement this by keeping several path lists, and then simply
77    ignoring the ones which are not relevant.  */
78
79 /* This holds all the -I directories.  */
80 static struct entry *include_dirs;
81
82 /* This holds the CLASSPATH environment variable.  */
83 static struct entry *classpath_env;
84
85 /* This holds the -classpath command-line option.  */
86 static struct entry *classpath_user;
87
88 /* This holds the default directories.  Some of these will have the
89    "system" flag set.  */
90 static struct entry *sys_dirs;
91
92 /* This holds the extensions path entries.  */
93 static struct entry *extensions;
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;
140      const char *filename;
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);
151   if (len > 4 && (strcmp (filename + len - 4, ".zip") == 0
152                   || strcmp (filename + len - 4, ".jar") == 0))
153     {
154       n->flags |= FLAG_ZIP;
155       /* If the user uses -classpath then he'll have to include
156          libgcj.jar in the value.  We check for this in a simplistic
157          way.  Symlinks will fool this test.  This is only used for
158          -MM and -MMD, so it probably isn't terribly important.  */
159       if (! strcmp (filename, LIBGCJ_ZIP_FILE))
160         n->flags |= FLAG_SYSTEM;
161     }
162
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)
167     {
168       char *f2 = (char *) alloca (len + 2);
169       strcpy (f2, filename);
170       f2[len] = DIR_SEPARATOR;
171       f2[len + 1] = '\0';
172       n->name = xstrdup (f2);
173       ++len;
174     }
175   else
176     n->name = xstrdup (filename);
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;
187      const char *cp;
188      int is_system;
189 {
190   const char *startp, *endp;
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             {
200               if (endp == startp)
201                 {
202                   buf[0] = '.';
203                   buf[1] = DIR_SEPARATOR;
204                   buf[2] = '\0';
205                 }
206               else
207                 {
208                   strncpy (buf, startp, endp - startp);
209                   buf[endp - startp] = '\0';
210                 }
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
223 static int init_done = 0;
224
225 /* Initialize the path module.  */
226 void
227 jcf_path_init ()
228 {
229   char *cp;
230   char *try, sep[2];
231   struct stat stat_b;
232   int found = 0, len;
233
234   if (init_done)
235     return;
236   init_done = 1;
237
238   sep[0] = DIR_SEPARATOR;
239   sep[1] = '\0';
240
241   GET_ENVIRONMENT (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/java 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);
259       strcat (try, "java");
260       strcat (try, sep);
261       strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar");
262       if (! stat (try, &stat_b))
263         {
264           add_entry (&sys_dirs, try, 1);
265           found = 1;
266           strcpy (&try[strlen (try)
267                       - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
268                   sep);
269           strcat (try, "ext");
270           strcat (try, sep);
271           if (! stat (try, &stat_b))
272             jcf_path_extdirs_arg (try);
273         }
274       else
275         {
276           strcpy (try + len, DIR_UP);
277           strcat (try, sep);
278           strcat (try, "share");
279           strcat (try, sep);
280           strcat (try, "java");
281           strcat (try, sep);
282           strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar");
283           if (! stat (try, &stat_b))
284             {
285               add_entry (&sys_dirs, try, 1);
286               found = 1;
287               strcpy (&try[strlen (try)
288                           - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
289                       sep);
290               strcat (try, "ext");
291               strcat (try, sep);
292               if (! stat (try, &stat_b))
293                 jcf_path_extdirs_arg (try);
294             }
295         }
296     }
297   if (! found)
298     {
299       /* Desperation: use the installed one.  */
300       char *extdirs;
301       add_entry (&sys_dirs, LIBGCJ_ZIP_FILE, 1);
302       extdirs = (char *) alloca (strlen (LIBGCJ_ZIP_FILE) + 1);
303       strcpy (extdirs, LIBGCJ_ZIP_FILE);
304       strcpy (&extdirs[strlen (LIBGCJ_ZIP_FILE)
305                       - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
306               "ext");
307       strcat (extdirs, sep);
308       if (! stat (extdirs, &stat_b))
309         jcf_path_extdirs_arg (extdirs);
310     }
311
312   GET_ENVIRONMENT (cp, "CLASSPATH");
313   add_path (&classpath_env, cp, 0);
314 }
315
316 /* Call this when -classpath is seen on the command line.
317    This overrides only the $CLASSPATH environment variable.
318  */
319 void
320 jcf_path_classpath_arg (path)
321      const char *path;
322 {
323   free_entry (&classpath_user);
324   add_path (&classpath_user, path, 0);
325 }
326
327 /* Call this when -bootclasspath is seen on the command line.
328  */
329 void
330 jcf_path_bootclasspath_arg (path)
331      const char *path;
332 {
333   free_entry (&sys_dirs);
334   add_path (&sys_dirs, path, 1);
335 }
336
337 /* Call this when -extdirs is seen on the command line.
338  */
339 void
340 jcf_path_extdirs_arg (cp)
341      const char *cp;
342 {
343   const char *startp, *endp;
344
345   free_entry (&extensions);
346
347   if (cp)
348     {
349       char *buf = (char *) alloca (strlen (cp) + 3);
350       startp = endp = cp;
351       while (1)
352         {
353           if (! *endp || *endp == PATH_SEPARATOR)
354             {
355               if (endp == startp)
356                 return;
357
358               strncpy (buf, startp, endp - startp);
359               buf[endp - startp] = '\0';
360
361               {  
362                 DIR *dirp = NULL;
363                 int dirname_length = strlen (buf);
364                 
365                 dirp = opendir (buf);
366                 if (dirp == NULL)
367                   return;
368                 
369                 for (;;)
370                   {
371                     struct dirent *direntp = readdir (dirp);
372                     
373                     if (!direntp)
374                       break;
375                     
376                     if (direntp->d_name[0] != '.')
377                       {
378                         char *name = 
379                           (char *) alloca (dirname_length
380                                            + strlen (direntp->d_name) + 2);
381                         strcpy (name, buf);
382                         if (name[dirname_length-1] != DIR_SEPARATOR)
383                           {
384                             name[dirname_length] = DIR_SEPARATOR;
385                             name[dirname_length+1] = 0;
386                           }
387                         strcat (name, direntp->d_name);
388                         add_entry (&extensions, name, 0);
389                       }
390                   }
391               }
392
393               if (! *endp)
394                 break;
395               ++endp;
396               startp = endp;
397             }
398           else
399             ++endp;
400         }
401     }
402 }
403
404 /* Call this when -I is seen on the command line.  */
405 void
406 jcf_path_include_arg (path)
407      const char *path;
408 {
409   add_entry (&include_dirs, path, 0);
410 }
411
412 /* We `seal' the path by linking everything into one big list.  Then
413    we provide a way to iterate through the sealed list.  If PRINT is
414    true then we print the final class path to stderr.  */
415 void
416 jcf_path_seal (print)
417      int print;
418 {
419   struct entry *secondary;
420
421   sealed = include_dirs;
422   include_dirs = NULL;
423
424   if (classpath_user)
425     {
426       secondary = classpath_user;
427       classpath_user = NULL;
428     }
429   else
430     {
431       if (! classpath_env)
432         add_entry (&classpath_env, ".", 0);
433
434       secondary = classpath_env;
435       classpath_env = NULL;
436     }
437
438
439   free_entry (&classpath_user);
440   free_entry (&classpath_env);
441
442   append_entry (&sealed, secondary);
443   append_entry (&sealed, sys_dirs);
444   append_entry (&sealed, extensions);
445   sys_dirs = NULL;
446   extensions = NULL;
447
448   if (print)
449     {
450       struct entry *ent;
451       fprintf (stderr, "Class path starts here:\n");
452       for (ent = sealed; ent; ent = ent->next)
453         {
454           fprintf (stderr, "    %s", ent->name);
455           if ((ent->flags & FLAG_SYSTEM))
456             fprintf (stderr, " (system)");
457           if ((ent->flags & FLAG_ZIP))
458             fprintf (stderr, " (zip)");
459           fprintf (stderr, "\n");
460         }
461     }
462 }
463
464 void *
465 jcf_path_start ()
466 {
467   return (void *) sealed;
468 }
469
470 void *
471 jcf_path_next (x)
472      void *x;
473 {
474   struct entry *ent = (struct entry *) x;
475   return (void *) ent->next;
476 }
477
478 /* We guarantee that the return path will either be a zip file, or it
479    will end with a directory separator.  */
480 char *
481 jcf_path_name (x)
482      void *x;
483 {
484   struct entry *ent = (struct entry *) x;
485   return ent->name;
486 }
487
488 int
489 jcf_path_is_zipfile (x)
490      void *x;
491 {
492   struct entry *ent = (struct entry *) x;
493   return (ent->flags & FLAG_ZIP);
494 }
495
496 int
497 jcf_path_is_system (x)
498      void *x;
499 {
500   struct entry *ent = (struct entry *) x;
501   return (ent->flags & FLAG_SYSTEM);
502 }
503
504 int
505 jcf_path_max_len ()
506 {
507   return longest_path;
508 }