jdk/src/share/bin/wildcard.c
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 /*
       
    27  * Class-Path Wildcards
       
    28  *
       
    29  * The syntax for wildcards is a single asterisk. The class path
       
    30  * foo/"*", e.g., loads all jar files in the directory named foo.
       
    31  * (This requires careful quotation when used in shell scripts.)
       
    32  *
       
    33  * Only files whose names end in .jar or .JAR are matched.
       
    34  * Files whose names end in .zip, or which have a particular
       
    35  * magic number, regardless of filename extension, are not
       
    36  * matched.
       
    37  *
       
    38  * Files are considered regardless of whether or not they are
       
    39  * "hidden" in the UNIX sense, i.e., have names beginning with '.'.
       
    40  *
       
    41  * A wildcard only matches jar files, not class files in the same
       
    42  * directory.  If you want to load both class files and jar files from
       
    43  * a single directory foo then you can say foo:foo/"*", or foo/"*":foo
       
    44  * if you want the jar files to take precedence.
       
    45  *
       
    46  * Subdirectories are not searched recursively, i.e., foo/"*" only
       
    47  * looks for jar files in foo, not in foo/bar, foo/baz, etc.
       
    48  *
       
    49  * Expansion of wildcards is done early, prior to the invocation of a
       
    50  * program's main method, rather than late, during the class-loading
       
    51  * process itself.  Each element of the input class path containing a
       
    52  * wildcard is replaced by the (possibly empty) sequence of elements
       
    53  * generated by enumerating the jar files in the named directory.  If
       
    54  * the directory foo contains a.jar, b.jar, and c.jar,
       
    55  * e.g., then the class path foo/"*" is expanded into
       
    56  * foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value
       
    57  * of the system property java.class.path.
       
    58  *
       
    59  * The order in which the jar files in a directory are enumerated in
       
    60  * the expanded class path is not specified and may vary from platform
       
    61  * to platform and even from moment to moment on the same machine.  A
       
    62  * well-constructed application should not depend upon any particular
       
    63  * order.  If a specific order is required then the jar files can be
       
    64  * enumerated explicitly in the class path.
       
    65  *
       
    66  * The CLASSPATH environment variable is not treated any differently
       
    67  * from the -classpath (equiv. -cp) command-line option,
       
    68  * i.e. wildcards are honored in all these cases.
       
    69  *
       
    70  * Class-path wildcards are not honored in the Class-Path jar-manifest
       
    71  * header.
       
    72  *
       
    73  * Class-path wildcards are honored not only by the Java launcher but
       
    74  * also by most other command-line tools that accept class paths, and
       
    75  * in particular by javac and javadoc.
       
    76  *
       
    77  * Class-path wildcards are not honored in any other kind of path, and
       
    78  * especially not in the bootstrap class path, which is a mere
       
    79  * artifact of our implementation and not something that developers
       
    80  * should use.
       
    81  *
       
    82  * Classpath wildcards are only expanded in the Java launcher code,
       
    83  * supporting the use of wildcards on the command line and in the
       
    84  * CLASSPATH environment variable.  We do not support the use of
       
    85  * wildcards by applications that embed the JVM.
       
    86  */
       
    87 
       
    88 #include <stddef.h>
       
    89 #include <stdio.h>
       
    90 #include <stdlib.h>
       
    91 #include <string.h>
       
    92 #include <sys/types.h>
       
    93 #include "java.h"       /* Strictly for PATH_SEPARATOR/FILE_SEPARATOR */
       
    94 #include "jli_util.h"
       
    95 
       
    96 #ifdef _WIN32
       
    97 #include <windows.h>
       
    98 #else /* Unix */
       
    99 #include <unistd.h>
       
   100 #include <dirent.h>
       
   101 #endif /* Unix */
       
   102 
       
   103 static int
       
   104 exists(const char* filename)
       
   105 {
       
   106 #ifdef _WIN32
       
   107     return _access(filename, 0) == 0;
       
   108 #else
       
   109     return access(filename, F_OK) == 0;
       
   110 #endif
       
   111 }
       
   112 
       
   113 #define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_)))
       
   114 
       
   115 /*
       
   116  * Wildcard directory iteration.
       
   117  * WildcardIterator_for(wildcard) returns an iterator.
       
   118  * Each call to that iterator's next() method returns the basename
       
   119  * of an entry in the wildcard's directory.  The basename's memory
       
   120  * belongs to the iterator.  The caller is responsible for prepending
       
   121  * the directory name and file separator, if necessary.
       
   122  * When done with the iterator, call the close method to clean up.
       
   123  */
       
   124 typedef struct WildcardIterator_* WildcardIterator;
       
   125 
       
   126 #ifdef _WIN32
       
   127 struct WildcardIterator_
       
   128 {
       
   129     HANDLE handle;
       
   130     char *firstFile; /* Stupid FindFirstFile...FindNextFile */
       
   131 };
       
   132 
       
   133 static WildcardIterator
       
   134 WildcardIterator_for(const char *wildcard)
       
   135 {
       
   136     WIN32_FIND_DATA find_data;
       
   137     WildcardIterator it = NEW_(WildcardIterator);
       
   138     HANDLE handle = FindFirstFile(wildcard, &find_data);
       
   139     if (handle == INVALID_HANDLE_VALUE)
       
   140         return NULL;
       
   141     it->handle = handle;
       
   142     it->firstFile = find_data.cFileName;
       
   143     return it;
       
   144 }
       
   145 
       
   146 static char *
       
   147 WildcardIterator_next(WildcardIterator it)
       
   148 {
       
   149     WIN32_FIND_DATA find_data;
       
   150     if (it->firstFile != NULL) {
       
   151         char *firstFile = it->firstFile;
       
   152         it->firstFile = NULL;
       
   153         return firstFile;
       
   154     }
       
   155     return FindNextFile(it->handle, &find_data)
       
   156         ? find_data.cFileName : NULL;
       
   157 }
       
   158 
       
   159 static void
       
   160 WildcardIterator_close(WildcardIterator it)
       
   161 {
       
   162     if (it) {
       
   163         FindClose(it->handle);
       
   164         JLI_MemFree(it->firstFile);
       
   165         JLI_MemFree(it);
       
   166     }
       
   167 }
       
   168 
       
   169 #else /* Unix */
       
   170 struct WildcardIterator_
       
   171 {
       
   172     DIR *dir;
       
   173 };
       
   174 
       
   175 static WildcardIterator
       
   176 WildcardIterator_for(const char *wildcard)
       
   177 {
       
   178     DIR *dir;
       
   179     int wildlen = JLI_StrLen(wildcard);
       
   180     if (wildlen < 2) {
       
   181         dir = opendir(".");
       
   182     } else {
       
   183         char *dirname = JLI_StringDup(wildcard);
       
   184         dirname[wildlen - 1] = '\0';
       
   185         dir = opendir(dirname);
       
   186         JLI_MemFree(dirname);
       
   187     }
       
   188     if (dir == NULL)
       
   189         return NULL;
       
   190     else {
       
   191         WildcardIterator it = NEW_(WildcardIterator);
       
   192         it->dir = dir;
       
   193         return it;
       
   194     }
       
   195 }
       
   196 
       
   197 static char *
       
   198 WildcardIterator_next(WildcardIterator it)
       
   199 {
       
   200     struct dirent* dirp = readdir(it->dir);
       
   201     return dirp ? dirp->d_name : NULL;
       
   202 }
       
   203 
       
   204 static void
       
   205 WildcardIterator_close(WildcardIterator it)
       
   206 {
       
   207     if (it) {
       
   208         closedir(it->dir);
       
   209         JLI_MemFree(it);
       
   210     }
       
   211 }
       
   212 #endif /* Unix */
       
   213 
       
   214 static int
       
   215 equal(const char *s1, const char *s2)
       
   216 {
       
   217     return JLI_StrCmp(s1, s2) == 0;
       
   218 }
       
   219 
       
   220 /*
       
   221  * FileList ADT - a dynamic list of C filenames
       
   222  */
       
   223 struct FileList_
       
   224 {
       
   225     char **files;
       
   226     int size;
       
   227     int capacity;
       
   228 };
       
   229 typedef struct FileList_ *FileList;
       
   230 
       
   231 static FileList
       
   232 FileList_new(int capacity)
       
   233 {
       
   234     FileList fl = NEW_(FileList);
       
   235     fl->capacity = capacity;
       
   236     fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0]));
       
   237     fl->size = 0;
       
   238     return fl;
       
   239 }
       
   240 
       
   241 
       
   242 
       
   243 static void
       
   244 FileList_free(FileList fl)
       
   245 {
       
   246     if (fl) {
       
   247         if (fl->files) {
       
   248             int i;
       
   249             for (i = 0; i < fl->size; i++)
       
   250                 JLI_MemFree(fl->files[i]);
       
   251             JLI_MemFree(fl->files);
       
   252         }
       
   253         JLI_MemFree(fl);
       
   254     }
       
   255 }
       
   256 
       
   257 static void
       
   258 FileList_ensureCapacity(FileList fl, int capacity)
       
   259 {
       
   260     if (fl->capacity < capacity) {
       
   261         while (fl->capacity < capacity)
       
   262             fl->capacity *= 2;
       
   263         fl->files = JLI_MemRealloc(fl->files,
       
   264                                fl->capacity * sizeof(fl->files[0]));
       
   265     }
       
   266 }
       
   267 
       
   268 static void
       
   269 FileList_add(FileList fl, char *file)
       
   270 {
       
   271     FileList_ensureCapacity(fl, fl->size+1);
       
   272     fl->files[fl->size++] = file;
       
   273 }
       
   274 
       
   275 static void
       
   276 FileList_addSubstring(FileList fl, const char *beg, int len)
       
   277 {
       
   278     char *filename = (char *) JLI_MemAlloc(len+1);
       
   279     memcpy(filename, beg, len);
       
   280     filename[len] = '\0';
       
   281     FileList_ensureCapacity(fl, fl->size+1);
       
   282     fl->files[fl->size++] = filename;
       
   283 }
       
   284 
       
   285 static char *
       
   286 FileList_join(FileList fl, char sep)
       
   287 {
       
   288     int i;
       
   289     int size;
       
   290     char *path;
       
   291     char *p;
       
   292     for (i = 0, size = 1; i < fl->size; i++)
       
   293         size += JLI_StrLen(fl->files[i]) + 1;
       
   294 
       
   295     path = JLI_MemAlloc(size);
       
   296 
       
   297     for (i = 0, p = path; i < fl->size; i++) {
       
   298         int len = JLI_StrLen(fl->files[i]);
       
   299         if (i > 0) *p++ = sep;
       
   300         memcpy(p, fl->files[i], len);
       
   301         p += len;
       
   302     }
       
   303     *p = '\0';
       
   304 
       
   305     return path;
       
   306 }
       
   307 
       
   308 static FileList
       
   309 FileList_split(const char *path, char sep)
       
   310 {
       
   311     const char *p, *q;
       
   312     int len = JLI_StrLen(path);
       
   313     int count;
       
   314     FileList fl;
       
   315     for (count = 1, p = path; p < path + len; p++)
       
   316         count += (*p == sep);
       
   317     fl = FileList_new(count);
       
   318     for (p = path;;) {
       
   319         for (q = p; q <= path + len; q++) {
       
   320             if (*q == sep || *q == '\0') {
       
   321                 FileList_addSubstring(fl, p, q - p);
       
   322                 if (*q == '\0')
       
   323                     return fl;
       
   324                 p = q + 1;
       
   325             }
       
   326         }
       
   327     }
       
   328 }
       
   329 
       
   330 static int
       
   331 isJarFileName(const char *filename)
       
   332 {
       
   333     int len = JLI_StrLen(filename);
       
   334     return (len >= 4) &&
       
   335         (filename[len - 4] == '.') &&
       
   336         (equal(filename + len - 3, "jar") ||
       
   337          equal(filename + len - 3, "JAR")) &&
       
   338         /* Paranoia: Maybe filename is "DIR:foo.jar" */
       
   339         (JLI_StrChr(filename, PATH_SEPARATOR) == NULL);
       
   340 }
       
   341 
       
   342 static char *
       
   343 wildcardConcat(const char *wildcard, const char *basename)
       
   344 {
       
   345     int wildlen = JLI_StrLen(wildcard);
       
   346     int baselen = JLI_StrLen(basename);
       
   347     char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
       
   348     /* Replace the trailing '*' with basename */
       
   349     memcpy(filename, wildcard, wildlen-1);
       
   350     memcpy(filename+wildlen-1, basename, baselen+1);
       
   351     return filename;
       
   352 }
       
   353 
       
   354 static FileList
       
   355 wildcardFileList(const char *wildcard)
       
   356 {
       
   357     const char *basename;
       
   358     FileList fl = FileList_new(16);
       
   359     WildcardIterator it = WildcardIterator_for(wildcard);
       
   360     if (it == NULL)
       
   361         return NULL;
       
   362     while ((basename = WildcardIterator_next(it)) != NULL)
       
   363         if (isJarFileName(basename))
       
   364             FileList_add(fl, wildcardConcat(wildcard, basename));
       
   365     WildcardIterator_close(it);
       
   366     return fl;
       
   367 }
       
   368 
       
   369 static int
       
   370 isWildcard(const char *filename)
       
   371 {
       
   372     int len = JLI_StrLen(filename);
       
   373     return (len > 0) &&
       
   374         (filename[len - 1] == '*') &&
       
   375         (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
       
   376         (! exists(filename));
       
   377 }
       
   378 
       
   379 static void
       
   380 FileList_expandWildcards(FileList fl)
       
   381 {
       
   382     int i, j;
       
   383     for (i = 0; i < fl->size; i++) {
       
   384         if (isWildcard(fl->files[i])) {
       
   385             FileList expanded = wildcardFileList(fl->files[i]);
       
   386             if (expanded != NULL && expanded->size > 0) {
       
   387                 JLI_MemFree(fl->files[i]);
       
   388                 FileList_ensureCapacity(fl, fl->size + expanded->size);
       
   389                 for (j = fl->size - 1; j >= i+1; j--)
       
   390                     fl->files[j+expanded->size-1] = fl->files[j];
       
   391                 for (j = 0; j < expanded->size; j++)
       
   392                     fl->files[i+j] = expanded->files[j];
       
   393                 i += expanded->size - 1;
       
   394                 fl->size += expanded->size - 1;
       
   395                 /* fl expropriates expanded's elements. */
       
   396                 expanded->size = 0;
       
   397             }
       
   398             FileList_free(expanded);
       
   399         }
       
   400     }
       
   401 }
       
   402 
       
   403 const char *
       
   404 JLI_WildcardExpandClasspath(const char *classpath)
       
   405 {
       
   406     char *expanded;
       
   407     FileList fl;
       
   408 
       
   409     if (JLI_StrChr(classpath, '*') == NULL)
       
   410         return classpath;
       
   411     fl = FileList_split(classpath, PATH_SEPARATOR);
       
   412     FileList_expandWildcards(fl);
       
   413     expanded = FileList_join(fl, PATH_SEPARATOR);
       
   414     FileList_free(fl);
       
   415     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0)
       
   416         printf("Expanded wildcards:\n"
       
   417                "    before: \"%s\"\n"
       
   418                "    after : \"%s\"\n",
       
   419                classpath, expanded);
       
   420     return expanded;
       
   421 }
       
   422 
       
   423 #ifdef DEBUG_WILDCARD
       
   424 static void
       
   425 FileList_print(FileList fl)
       
   426 {
       
   427     int i;
       
   428     putchar('[');
       
   429     for (i = 0; i < fl->size; i++) {
       
   430         if (i > 0) printf(", ");
       
   431         printf("\"%s\"",fl->files[i]);
       
   432     }
       
   433     putchar(']');
       
   434 }
       
   435 
       
   436 static void
       
   437 wildcardExpandArgv(const char ***argv)
       
   438 {
       
   439     int i;
       
   440     for (i = 0; (*argv)[i]; i++) {
       
   441         if (equal((*argv)[i], "-cp") ||
       
   442             equal((*argv)[i], "-classpath")) {
       
   443             i++;
       
   444             (*argv)[i] = wildcardExpandClasspath((*argv)[i]);
       
   445         }
       
   446     }
       
   447 }
       
   448 
       
   449 static void
       
   450 debugPrintArgv(char *argv[])
       
   451 {
       
   452     int i;
       
   453     putchar('[');
       
   454     for (i = 0; argv[i]; i++) {
       
   455         if (i > 0) printf(", ");
       
   456         printf("\"%s\"", argv[i]);
       
   457     }
       
   458     printf("]\n");
       
   459 }
       
   460 
       
   461 int
       
   462 main(int argc, char *argv[])
       
   463 {
       
   464     argv[0] = "java";
       
   465     wildcardExpandArgv((const char***)&argv);
       
   466     debugPrintArgv(argv);
       
   467     /* execvp("java", argv); */
       
   468     return 0;
       
   469 }
       
   470 #endif /* DEBUG_WILDCARD */
       
   471 
       
   472 /* Cute little perl prototype implementation....
       
   473 
       
   474 my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":";
       
   475 
       
   476 sub expand($) {
       
   477   opendir DIR, $_[0] or return $_[0];
       
   478   join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR;
       
   479 }
       
   480 
       
   481 sub munge($) {
       
   482   join $sep,
       
   483     map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0];
       
   484 }
       
   485 
       
   486 for (my $i = 0; $i < @ARGV - 1; $i++) {
       
   487   $ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/;
       
   488 }
       
   489 
       
   490 $ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH};
       
   491 @ARGV = ("java", @ARGV);
       
   492 print "@ARGV\n";
       
   493 exec @ARGV;
       
   494 
       
   495 */