OSDN Git Service

* Make-lang.in, boehm.c, buffer.c,
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-path.c
index c92cf14..ddb31a5 100644 (file)
@@ -1,19 +1,21 @@
 /* Handle CLASSPATH, -classpath, and path searching.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
 
-   Copyright (C) 1998, 1999  Free Software Foundation, Inc.
+This file is part of GCC.
 
-This program is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-This program is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  
 
@@ -25,14 +27,12 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
-#include "jcf.h"
-
-/* Some boilerplate that really belongs in a header.  */
+#include <dirent.h>
 
-#ifndef GET_ENV_PATH_LIST
-#define GET_ENV_PATH_LIST(VAR,NAME)    do { (VAR) = getenv (NAME); } while (0)
-#endif
+#include "jcf.h"
 
 /* By default, colon separates directories in a path.  */
 #ifndef PATH_SEPARATOR
@@ -43,6 +43,10 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #define DIR_SEPARATOR '/'
 #endif
 
+#ifndef DIR_UP
+#define DIR_UP ".."
+#endif
+
 \f
 
 /* Possible flag values.  */
@@ -58,17 +62,19 @@ struct entry
   struct entry *next;
 };
 
-static void free_entry PROTO ((struct entry **));
-static void append_entry PROTO ((struct entry **, struct entry *));
-static void add_entry PROTO ((struct entry **, const char *, int));
-static void add_path PROTO ((struct entry **, const char *, int));
+static void free_entry PARAMS ((struct entry **));
+static void append_entry PARAMS ((struct entry **, struct entry *));
+static void add_entry PARAMS ((struct entry **, const char *, int));
+static void add_path PARAMS ((struct entry **, const char *, int));
 
 /* We support several different ways to set the class path.
 
-   built-in system directory (only libgcj.zip)
+   built-in system directory (only libgcj.jar)
    CLASSPATH environment variable
-   -CLASSPATH overrides CLASSPATH
-   -classpath option - overrides CLASSPATH, -CLASSPATH, and built-in
+   -classpath option overrides $CLASSPATH
+   -CLASSPATH option is a synonym for -classpath (for compatibility)
+   -bootclasspath overrides built-in
+   -extdirs sets the extensions directory path (overrides built-in)
    -I prepends path to list
 
    We implement this by keeping several path lists, and then simply
@@ -80,16 +86,16 @@ static struct entry *include_dirs;
 /* This holds the CLASSPATH environment variable.  */
 static struct entry *classpath_env;
 
-/* This holds the -CLASSPATH command-line option.  */
-static struct entry *classpath_u;
-
 /* This holds the -classpath command-line option.  */
-static struct entry *classpath_l;
+static struct entry *classpath_user;
 
 /* This holds the default directories.  Some of these will have the
    "system" flag set.  */
 static struct entry *sys_dirs;
 
+/* This holds the extensions path entries.  */
+static struct entry *extensions;
+
 /* This is the sealed list.  It is just a combination of other lists.  */
 static struct entry *sealed;
 
@@ -141,7 +147,7 @@ add_entry (entp, filename, is_system)
   int len;
   struct entry *n;
 
-  n = (struct entry *) ALLOC (sizeof (struct entry));
+  n = ALLOC (sizeof (struct entry));
   n->flags = is_system ? FLAG_SYSTEM : 0;
   n->next = NULL;
 
@@ -151,7 +157,7 @@ add_entry (entp, filename, is_system)
     {
       n->flags |= FLAG_ZIP;
       /* If the user uses -classpath then he'll have to include
-        libgcj.zip in the value.  We check for this in a simplistic
+        libgcj.jar in the value.  We check for this in a simplistic
         way.  Symlinks will fool this test.  This is only used for
         -MM and -MMD, so it probably isn't terribly important.  */
       if (! strcmp (filename, LIBGCJ_ZIP_FILE))
@@ -163,15 +169,15 @@ add_entry (entp, filename, is_system)
      work more easily.  Eww.  */
   if (filename[len - 1] != '/' && filename[len - 1] != DIR_SEPARATOR)
     {
-      char *f2 = (char *) alloca (len + 2);
+      char *f2 = alloca (len + 2);
       strcpy (f2, filename);
       f2[len] = DIR_SEPARATOR;
       f2[len + 1] = '\0';
-      n->name = strdup (f2);
+      n->name = xstrdup (f2);
       ++len;
     }
   else
-    n->name = strdup (filename);
+    n->name = xstrdup (filename);
 
   if (len > longest_path)
     longest_path = len;
@@ -189,7 +195,7 @@ add_path (entp, cp, is_system)
 
   if (cp)
     {
-      char *buf = (char *) alloca (strlen (cp) + 3);
+      char *buf = alloca (strlen (cp) + 3);
       startp = endp = cp;
       while (1)
        {
@@ -218,35 +224,184 @@ add_path (entp, cp, is_system)
     }
 }
 
+static int init_done = 0;
+
 /* Initialize the path module.  */
 void
 jcf_path_init ()
 {
   char *cp;
+  char *try, sep[2];
+  struct stat stat_b;
+  int found = 0, len;
+
+  if (init_done)
+    return;
+  init_done = 1;
+
+  sep[0] = DIR_SEPARATOR;
+  sep[1] = '\0';
 
-  add_entry (&sys_dirs, ".", 0);
-  add_entry (&sys_dirs, LIBGCJ_ZIP_FILE, 1);
+  GET_ENVIRONMENT (cp, "GCC_EXEC_PREFIX");
+  if (cp)
+    {
+      try = alloca (strlen (cp) + 50);
+      /* The exec prefix can be something like
+        /usr/local/bin/../lib/gcc-lib/.  We want to change this
+        into a pointer to the share/java directory.  We support two
+        configurations: one where prefix and exec-prefix are the
+        same, and one where exec-prefix is `prefix/SOMETHING'.  */
+      strcpy (try, cp);
+      strcat (try, DIR_UP);
+      strcat (try, sep);
+      strcat (try, DIR_UP);
+      strcat (try, sep);
+      len = strlen (try);
+
+      strcpy (try + len, "share");
+      strcat (try, sep);
+      strcat (try, "java");
+      strcat (try, sep);
+      strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar");
+      if (! stat (try, &stat_b))
+       {
+         add_entry (&sys_dirs, try, 1);
+         found = 1;
+         strcpy (&try[strlen (try)
+                     - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
+                 sep);
+         strcat (try, "ext");
+         strcat (try, sep);
+         if (! stat (try, &stat_b))
+           jcf_path_extdirs_arg (try);
+       }
+      else
+       {
+         strcpy (try + len, DIR_UP);
+         strcat (try, sep);
+         strcat (try, "share");
+         strcat (try, sep);
+         strcat (try, "java");
+         strcat (try, sep);
+         strcat (try, "libgcj-" DEFAULT_TARGET_VERSION ".jar");
+         if (! stat (try, &stat_b))
+           {
+             add_entry (&sys_dirs, try, 1);
+             found = 1;
+             strcpy (&try[strlen (try)
+                         - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
+                     sep);
+             strcat (try, "ext");
+             strcat (try, sep);
+             if (! stat (try, &stat_b))
+               jcf_path_extdirs_arg (try);
+           }
+       }
+    }
+  if (! found)
+    {
+      /* Desperation: use the installed one.  */
+      char *extdirs;
+      add_entry (&sys_dirs, LIBGCJ_ZIP_FILE, 1);
+      extdirs = alloca (strlen (LIBGCJ_ZIP_FILE) + 1);
+      strcpy (extdirs, LIBGCJ_ZIP_FILE);
+      strcpy (&extdirs[strlen (LIBGCJ_ZIP_FILE)
+                     - strlen ("libgcj-" DEFAULT_TARGET_VERSION ".jar")],
+             "ext");
+      strcat (extdirs, sep);
+      if (! stat (extdirs, &stat_b))
+       jcf_path_extdirs_arg (extdirs);
+    }
 
-  GET_ENV_PATH_LIST (cp, "CLASSPATH");
+  GET_ENVIRONMENT (cp, "CLASSPATH");
   add_path (&classpath_env, cp, 0);
 }
 
-/* Call this when -classpath is seen on the command line.  */
+/* Call this when -classpath is seen on the command line.
+   This overrides only the $CLASSPATH environment variable.
+ */
 void
 jcf_path_classpath_arg (path)
      const char *path;
 {
-  free_entry (&classpath_l);
-  add_path (&classpath_l, path, 0);
+  free_entry (&classpath_user);
+  add_path (&classpath_user, path, 0);
 }
 
-/* Call this when -CLASSPATH is seen on the command line.  */
+/* Call this when -bootclasspath is seen on the command line.
+ */
 void
-jcf_path_CLASSPATH_arg (path)
+jcf_path_bootclasspath_arg (path)
      const char *path;
 {
-  free_entry (&classpath_u);
-  add_path (&classpath_u, path, 0);
+  free_entry (&sys_dirs);
+  add_path (&sys_dirs, path, 1);
+}
+
+/* Call this when -extdirs is seen on the command line.
+ */
+void
+jcf_path_extdirs_arg (cp)
+     const char *cp;
+{
+  const char *startp, *endp;
+
+  free_entry (&extensions);
+
+  if (cp)
+    {
+      char *buf = alloca (strlen (cp) + 3);
+      startp = endp = cp;
+      while (1)
+       {
+         if (! *endp || *endp == PATH_SEPARATOR)
+           {
+             if (endp == startp)
+               return;
+
+             strncpy (buf, startp, endp - startp);
+             buf[endp - startp] = '\0';
+
+             {  
+               DIR *dirp = NULL;
+               int dirname_length = strlen (buf);
+               
+               dirp = opendir (buf);
+               if (dirp == NULL)
+                 return;
+               
+               for (;;)
+                 {
+                   struct dirent *direntp = readdir (dirp);
+                   
+                   if (!direntp)
+                     break;
+                   
+                   if (direntp->d_name[0] != '.')
+                     {
+                       char *name = alloca (dirname_length
+                                            + strlen (direntp->d_name) + 2);
+                       strcpy (name, buf);
+                       if (name[dirname_length-1] != DIR_SEPARATOR)
+                         {
+                           name[dirname_length] = DIR_SEPARATOR;
+                           name[dirname_length+1] = 0;
+                         }
+                       strcat (name, direntp->d_name);
+                       add_entry (&extensions, name, 0);
+                     }
+                 }
+             }
+
+             if (! *endp)
+               break;
+             ++endp;
+             startp = endp;
+           }
+         else
+           ++endp;
+       }
+    }
 }
 
 /* Call this when -I is seen on the command line.  */
@@ -258,46 +413,55 @@ jcf_path_include_arg (path)
 }
 
 /* We `seal' the path by linking everything into one big list.  Then
-   we provide a way to iterate through the sealed list.  */
+   we provide a way to iterate through the sealed list.  If PRINT is
+   true then we print the final class path to stderr.  */
 void
-jcf_path_seal ()
+jcf_path_seal (print)
+     int print;
 {
-  int do_system = 1;
   struct entry *secondary;
 
   sealed = include_dirs;
   include_dirs = NULL;
 
-  if (classpath_l)
+  if (classpath_user)
     {
-      secondary = classpath_l;
-      classpath_l = NULL;
-      do_system = 0;
-    }
-  else if (classpath_u)
-    {
-      secondary = classpath_u;
-      classpath_u = NULL;
+      secondary = classpath_user;
+      classpath_user = NULL;
     }
   else
     {
+      if (! classpath_env)
+       add_entry (&classpath_env, ".", 0);
+
       secondary = classpath_env;
       classpath_env = NULL;
     }
 
-  free_entry (&classpath_l);
-  free_entry (&classpath_u);
+
+  free_entry (&classpath_user);
   free_entry (&classpath_env);
 
   append_entry (&sealed, secondary);
+  append_entry (&sealed, sys_dirs);
+  append_entry (&sealed, extensions);
+  sys_dirs = NULL;
+  extensions = NULL;
 
-  if (do_system)
+  if (print)
     {
-      append_entry (&sealed, sys_dirs);
-      sys_dirs = NULL;
+      struct entry *ent;
+      fprintf (stderr, "Class path starts here:\n");
+      for (ent = sealed; ent; ent = ent->next)
+       {
+         fprintf (stderr, "    %s", ent->name);
+         if ((ent->flags & FLAG_SYSTEM))
+           fprintf (stderr, " (system)");
+         if ((ent->flags & FLAG_ZIP))
+           fprintf (stderr, " (zip)");
+         fprintf (stderr, "\n");
+       }
     }
-  else
-    free_entry (&sys_dirs);
 }
 
 void *