OSDN Git Service

Make --CLASSPATH by a synonym for --classpath and -classpath.
[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 "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
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
46 #ifndef DIR_UP
47 #define DIR_UP ".."
48 #endif
49
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
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));
69
70 /* We support several different ways to set the class path.
71
72    built-in system directory (only libgcj.jar)
73    CLASSPATH environment variable
74    -classpath option overrides $CLASSPATH
75    -CLASSPATH option is a synonym for -classpath (for compatibility)
76    -bootclasspath overrides built-in
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
88 /* This holds the -classpath command-line option.  */
89 static struct entry *classpath_user;
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;
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_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);
259       strcat (try, "libgcj.jar");
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);
271           strcat (try, "libgcj.jar");
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     }
284
285   GET_ENV_PATH_LIST (cp, "CLASSPATH");
286   add_path (&classpath_env, cp, 0);
287 }
288
289 /* Call this when -classpath is seen on the command line.
290    This overrides only the $CLASSPATH environment variable.
291  */
292 void
293 jcf_path_classpath_arg (path)
294      const char *path;
295 {
296   free_entry (&classpath_user);
297   add_path (&classpath_user, path, 0);
298 }
299
300 /* Call this when -bootclasspath is seen on the command line.
301  */
302 void
303 jcf_path_bootclasspath_arg (path)
304      const char *path;
305 {
306   free_entry (&sys_dirs);
307   add_path (&sys_dirs, path, 1);
308 }
309
310 /* Call this when -I is seen on the command line.  */
311 void
312 jcf_path_include_arg (path)
313      const char *path;
314 {
315   add_entry (&include_dirs, path, 0);
316 }
317
318 /* We `seal' the path by linking everything into one big list.  Then
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.  */
321 void
322 jcf_path_seal (print)
323      int print;
324 {
325   struct entry *secondary;
326
327   sealed = include_dirs;
328   include_dirs = NULL;
329
330   if (classpath_user)
331     {
332       secondary = classpath_user;
333       classpath_user = NULL;
334     }
335   else
336     {
337       if (! classpath_env)
338         add_entry (&classpath_env, ".", 0);
339
340       secondary = classpath_env;
341       classpath_env = NULL;
342     }
343
344
345   free_entry (&classpath_user);
346   free_entry (&classpath_env);
347
348   append_entry (&sealed, secondary);
349   append_entry (&sealed, sys_dirs);
350   sys_dirs = NULL;
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     }
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 }