OSDN Git Service

2006-01-24 Dirk Mueller <dmueller@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-path.c
index 6e88496..5f509b7 100644 (file)
@@ -1,21 +1,23 @@
 /* Handle CLASSPATH, -classpath, and path searching.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
 
-   Copyright (C) 1998  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
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  
 
 Java and all Java-based marks are trademarks or registered trademarks
 of Sun Microsystems, Inc. in the United States and other countries.
@@ -23,24 +25,17 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 /* Written by Tom Tromey <tromey@cygnus.com>, October 1998.  */
 
-#include <config.h>
+#include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
-#include "jcf.h"
-
-/* Some boilerplate that really belongs in a header.  */
-
-#ifndef GET_ENV_PATH_LIST
-#define GET_ENV_PATH_LIST(VAR,NAME)    do { (VAR) = getenv (NAME); } while (0)
-#endif
+#include <dirent.h>
 
-/* By default, colon separates directories in a path.  */
-#ifndef PATH_SEPARATOR
-#define PATH_SEPARATOR ':'
-#endif
+#include "jcf.h"
 
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
+#ifndef DIR_UP
+#define DIR_UP ".."
 #endif
 
 \f
@@ -58,12 +53,19 @@ struct entry
   struct entry *next;
 };
 
+static void free_entry (struct entry **);
+static void append_entry (struct entry **, struct entry *);
+static void add_entry (struct entry **, const char *, int);
+static void add_path (struct entry **, const char *, int);
+
 /* We support several different ways to set the class path.
 
-   built-in system directory (only libjava.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
@@ -75,16 +77,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;
 
@@ -94,8 +96,7 @@ static int longest_path = 0;
 \f
 
 static void
-free_entry (entp)
-     struct entry **entp;
+free_entry (struct entry **entp)
 {
   struct entry *e, *n;
 
@@ -109,9 +110,7 @@ free_entry (entp)
 }
 
 static void
-append_entry (entp, ent)
-     struct entry **entp;
-     struct entry *ent;
+append_entry (struct entry **entp, struct entry *ent)
 {
   /* It doesn't matter if this is slow, since it is run only at
      startup, and then infrequently.  */
@@ -128,41 +127,43 @@ append_entry (entp, ent)
 }
 
 static void
-add_entry (entp, filename, is_system)
-     struct entry **entp;
-     char *filename;
-     int is_system;
+add_entry (struct entry **entp, const char *filename, int 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;
 
   len = strlen (filename);
-  if (len > 4 && ! strcmp (filename - 4, ".zip"))
+
+  if (len > 4 && (FILENAME_CMP (filename + len - 4, ".zip") == 0
+                 || FILENAME_CMP (filename + len - 4, ".jar") == 0))
     {
       n->flags |= FLAG_ZIP;
       /* If the user uses -classpath then he'll have to include
-        libjava.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, LIBJAVA_ZIP_FILE))
+      if (! FILENAME_CMP (filename, LIBGCJ_ZIP_FILE))
        n->flags |= FLAG_SYSTEM;
     }
 
-  if (filename[len - 1] != '/' && filename[len - 1] != DIR_SEPARATOR)
+  /* Note that we add a trailing separator to `.zip' names as well.
+     This is a little hack that lets the searching code in jcf-io.c
+     work more easily.  Eww.  */
+  if (! IS_DIR_SEPARATOR (filename[len - 1]))
     {
-      char *f2 = (char *) alloca (len + 1);
+      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;
@@ -171,35 +172,29 @@ add_entry (entp, filename, is_system)
 }
 
 static void
-add_path (entp, cp, is_system)
-     struct entry **entp;
-     char *cp;
-     int is_system;
+add_path (struct entry **entp, const char *cp, int is_system)
 {
-  char *startp, *endp;
+  const char *startp, *endp;
 
   if (cp)
     {
-      char *buf = (char *) alloca (strlen (cp) + 3);
+      char *buf = alloca (strlen (cp) + 3);
       startp = endp = cp;
       while (1)
        {
          if (! *endp || *endp == PATH_SEPARATOR)
            {
-             strncpy (buf, startp, endp - startp);
              if (endp == startp)
                {
                  buf[0] = '.';
                  buf[1] = DIR_SEPARATOR;
                  buf[2] = '\0';
                }
-             else if (endp[-1] != '/' && endp[1] != DIR_SEPARATOR)
+             else
                {
-                 buf[endp - startp] = DIR_SEPARATOR;
-                 buf[endp - startp + 1] = '\0';
+                 strncpy (buf, startp, endp - startp);
+                 buf[endp - startp] = '\0';
                }
-             else
-               buf[endp - startp] = '\0';
              add_entry (entp, buf, is_system);
              if (! *endp)
                break;
@@ -212,97 +207,251 @@ add_path (entp, cp, is_system)
     }
 }
 
+static int init_done = 0;
+
 /* Initialize the path module.  */
 void
-jcf_path_init ()
+jcf_path_init (void)
 {
   char *cp;
+  char *try, sep[2];
+  struct stat stat_b;
+  int found = 0, len;
+
+  if (init_done)
+    return;
+  init_done = 1;
 
-  add_entry (&sys_dirs, ".", 0);
-  add_entry (&sys_dirs, LIBJAVA_ZIP_FILE, 1);
+  sep[0] = DIR_SEPARATOR;
+  sep[1] = '\0';
 
-  GET_ENV_PATH_LIST (cp, "CLASSPATH");
+  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_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 (const char *path)
+{
+  free_entry (&classpath_user);
+  add_path (&classpath_user, path, 0);
+}
+
+/* Call this when -bootclasspath is seen on the command line.
+ */
 void
-jcf_path_classpath_arg (path)
-     char *path;
+jcf_path_bootclasspath_arg (const char *path)
 {
-  free_entry (&classpath_l);
-  add_path (&classpath_l, path, 0);
+  free_entry (&sys_dirs);
+  add_path (&sys_dirs, path, 1);
 }
 
-/* Call this when -CLASSPATH is seen on the command line.  */
+/* Call this when -extdirs is seen on the command line.
+ */
 void
-jcf_path_CLASSPATH_arg (path)
-     char *path;
+jcf_path_extdirs_arg (const char *cp)
 {
-  free_entry (&classpath_u);
-  add_path (&classpath_u, path, 0);
+  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 (! IS_DIR_SEPARATOR (name[dirname_length-1]))
+                         {
+                           name[dirname_length] = DIR_SEPARATOR;
+                           name[dirname_length+1] = 0;
+                         }
+                       strcat (name, direntp->d_name);
+                       add_entry (&extensions, name, 0);
+                     }
+                 }
+               if (dirp)
+                 closedir (dirp);
+             }
+
+             if (! *endp)
+               break;
+             ++endp;
+             startp = endp;
+           }
+         else
+           ++endp;
+       }
+    }
 }
 
 /* Call this when -I is seen on the command line.  */
 void
-jcf_path_include_arg (path)
-     char *path;
+jcf_path_include_arg (const char *path)
 {
   add_entry (&include_dirs, path, 0);
 }
 
 /* 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 (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 *
-jcf_path_start ()
+jcf_path_start (void)
 {
   return (void *) sealed;
 }
 
 void *
-jcf_path_next (x)
-     void *x;
+jcf_path_next (void *x)
 {
   struct entry *ent = (struct entry *) x;
   return (void *) ent->next;
@@ -311,31 +460,28 @@ jcf_path_next (x)
 /* We guarantee that the return path will either be a zip file, or it
    will end with a directory separator.  */
 char *
-jcf_path_name (x)
-     void *x;
+jcf_path_name (void *x)
 {
   struct entry *ent = (struct entry *) x;
   return ent->name;
 }
 
 int
-jcf_path_is_zipfile (x)
-     void *x;
+jcf_path_is_zipfile (void *x)
 {
   struct entry *ent = (struct entry *) x;
   return (ent->flags & FLAG_ZIP);
 }
 
 int
-jcf_path_is_system (x)
-     void *x;
+jcf_path_is_system (void *x)
 {
   struct entry *ent = (struct entry *) x;
   return (ent->flags & FLAG_SYSTEM);
 }
 
 int
-jcf_path_max_len ()
+jcf_path_max_len (void)
 {
   return longest_path;
 }