OSDN Git Service

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