1/* Handle CLASSPATH, -classpath, and path searching. 2 3 Copyright (C) 1998, 1999 Free Software Foundation, Inc. 4 5This program is free software; you can redistribute it and/or modify 6it under the terms of the GNU General Public License as published by 7the Free Software Foundation; either version 2, or (at your option) 8any later version. 9 10This program is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with GNU CC; see the file COPYING. If not, write to 17the Free Software Foundation, 59 Temple Place - Suite 330, 18Boston, MA 02111-1307, USA. 19 20Java and all Java-based marks are trademarks or registered trademarks 21of Sun Microsystems, Inc. in the United States and other countries. 22The 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 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. */ 54struct entry 55{ 56 char *name; 57 int flags; 58 struct entry *next; 59}; 60 61/* We support several different ways to set the class path. 62 63 built-in system directory (only libgcj.zip) 64 CLASSPATH environment variable 65 -CLASSPATH overrides CLASSPATH 66 -classpath option - overrides CLASSPATH, -CLASSPATH, and 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. */ 73static struct entry *include_dirs; 74 75/* This holds the CLASSPATH environment variable. */ 76static struct entry *classpath_env; 77 78/* This holds the -CLASSPATH command-line option. */ 79static struct entry *classpath_u; 80 81/* This holds the -classpath command-line option. */ 82static struct entry *classpath_l; 83 84/* This holds the default directories. Some of these will have the 85 "system" flag set. */ 86static struct entry *sys_dirs; 87 88/* This is the sealed list. It is just a combination of other lists. */ 89static struct entry *sealed; 90 91/* We keep track of the longest path we've seen. */ 92static int longest_path = 0; 93 94 95 96static void 97free_entry (entp) 98 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 111static void 112append_entry (entp, ent) 113 struct entry **entp; 114 struct entry *ent; 115{ 116 /* It doesn't matter if this is slow, since it is run only at 117 startup, and then infrequently. */ 118 struct entry *e; 119 120 /* Find end of list. */ 121 for (e = *entp; e && e->next; e = e->next) 122 ; 123 124 if (e) 125 e->next = ent; 126 else 127 *entp = ent; 128} 129 130static void 131add_entry (entp, filename, is_system) 132 struct entry **entp; 133 char *filename; 134 int is_system; 135{ 136 int len; 137 struct entry *n; 138 139 n = (struct entry *) ALLOC (sizeof (struct entry)); 140 n->flags = is_system ? FLAG_SYSTEM : 0; 141 n->next = NULL; 142 143 len = strlen (filename); 144 if (len > 4 && (strcmp (filename + len - 4, ".zip") == 0 145 || strcmp (filename + len - 4, ".jar") == 0)) 146 { 147 n->flags |= FLAG_ZIP; 148 /* If the user uses -classpath then he'll have to include 149 libgcj.zip in the value. We check for this in a simplistic 150 way. Symlinks will fool this test. This is only used for 151 -MM and -MMD, so it probably isn't terribly important. */ 152 if (! strcmp (filename, LIBGCJ_ZIP_FILE)) 153 n->flags |= FLAG_SYSTEM; 154 } 155 156 /* Note that we add a trailing separator to `.zip' names as well. 157 This is a little hack that lets the searching code in jcf-io.c 158 work more easily. Eww. */ 159 if (filename[len - 1] != '/' && filename[len - 1] != DIR_SEPARATOR) 160 { 161 char *f2 = (char *) alloca (len + 2); 162 strcpy (f2, filename); 163 f2[len] = DIR_SEPARATOR; 164 f2[len + 1] = '\0'; 165 n->name = strdup (f2); 166 ++len; 167 } 168 else 169 n->name = strdup (filename); 170 171 if (len > longest_path) 172 longest_path = len; 173 174 append_entry (entp, n); 175} 176 177static void 178add_path (entp, cp, is_system) 179 struct entry **entp; 180 char *cp; 181 int is_system; 182{ 183 char *startp, *endp; 184 185 if (cp) 186 { 187 char *buf = (char *) alloca (strlen (cp) + 3); 188 startp = endp = cp; 189 while (1) 190 { 191 if (! *endp || *endp == PATH_SEPARATOR) 192 { 193 if (endp == startp) 194 { 195 buf[0] = '.'; 196 buf[1] = DIR_SEPARATOR; 197 buf[2] = '\0'; 198 } 199 else 200 { 201 strncpy (buf, startp, endp - startp); 202 buf[endp - startp] = '\0'; 203 } 204 add_entry (entp, buf, is_system); 205 if (! *endp) 206 break; 207 ++endp; 208 startp = endp; 209 } 210 else 211 ++endp; 212 } 213 } 214} 215 216/* Initialize the path module. */ 217void 218jcf_path_init () 219{ 220 char *cp; 221 222 add_entry (&sys_dirs, ".", 0); 223 add_entry (&sys_dirs, LIBGCJ_ZIP_FILE, 1); 224 225 GET_ENV_PATH_LIST (cp, "CLASSPATH"); 226 add_path (&classpath_env, cp, 0); 227} 228 229/* Call this when -classpath is seen on the command line. */ 230void 231jcf_path_classpath_arg (path) 232 char *path; 233{ 234 free_entry (&classpath_l); 235 add_path (&classpath_l, path, 0); 236} 237 238/* Call this when -CLASSPATH is seen on the command line. */ 239void 240jcf_path_CLASSPATH_arg (path) 241 char *path; 242{ 243 free_entry (&classpath_u); 244 add_path (&classpath_u, path, 0); 245} 246 247/* Call this when -I is seen on the command line. */ 248void 249jcf_path_include_arg (path) 250 char *path; 251{ 252 add_entry (&include_dirs, path, 0); 253} 254 255/* We `seal' the path by linking everything into one big list. Then 256 we provide a way to iterate through the sealed list. */ 257void 258jcf_path_seal () 259{ 260 int do_system = 1; 261 struct entry *secondary; 262 263 sealed = include_dirs; 264 include_dirs = NULL; 265 266 if (classpath_l) 267 { 268 secondary = classpath_l; 269 classpath_l = NULL; 270 do_system = 0; 271 } 272 else if (classpath_u) 273 { 274 secondary = classpath_u; 275 classpath_u = NULL; 276 } 277 else 278 { 279 secondary = classpath_env; 280 classpath_env = NULL; 281 } 282 283 free_entry (&classpath_l); 284 free_entry (&classpath_u); 285 free_entry (&classpath_env); 286 287 append_entry (&sealed, secondary); 288 289 if (do_system) 290 { 291 append_entry (&sealed, sys_dirs); 292 sys_dirs = NULL; 293 } 294 else 295 free_entry (&sys_dirs); 296} 297 298void * 299jcf_path_start () 300{ 301 return (void *) sealed; 302} 303 304void * 305jcf_path_next (x) 306 void *x; 307{ 308 struct entry *ent = (struct entry *) x; 309 return (void *) ent->next; 310} 311 312/* We guarantee that the return path will either be a zip file, or it 313 will end with a directory separator. */ 314char * 315jcf_path_name (x) 316 void *x; 317{ 318 struct entry *ent = (struct entry *) x; 319 return ent->name; 320} 321 322int 323jcf_path_is_zipfile (x) 324 void *x; 325{ 326 struct entry *ent = (struct entry *) x; 327 return (ent->flags & FLAG_ZIP); 328} 329 330int 331jcf_path_is_system (x) 332 void *x; 333{ 334 struct entry *ent = (struct entry *) x; 335 return (ent->flags & FLAG_SYSTEM); 336} 337 338int 339jcf_path_max_len () 340{ 341 return longest_path; 342} 343