OSDN Git Service

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