src/share/tools/launcher/wildcard.c

changeset 2327
cb2d0a362639
child 4887
bad3bed4b323
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/tools/launcher/wildcard.c	Thu Dec 02 05:45:54 2010 -0800
     1.3 @@ -0,0 +1,494 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +/*
    1.29 + * Class-Path Wildcards
    1.30 + *
    1.31 + * The syntax for wildcards is a single asterisk. The class path
    1.32 + * foo/"*", e.g., loads all jar files in the directory named foo.
    1.33 + * (This requires careful quotation when used in shell scripts.)
    1.34 + *
    1.35 + * Only files whose names end in .jar or .JAR are matched.
    1.36 + * Files whose names end in .zip, or which have a particular
    1.37 + * magic number, regardless of filename extension, are not
    1.38 + * matched.
    1.39 + *
    1.40 + * Files are considered regardless of whether or not they are
    1.41 + * "hidden" in the UNIX sense, i.e., have names beginning with '.'.
    1.42 + *
    1.43 + * A wildcard only matches jar files, not class files in the same
    1.44 + * directory.  If you want to load both class files and jar files from
    1.45 + * a single directory foo then you can say foo:foo/"*", or foo/"*":foo
    1.46 + * if you want the jar files to take precedence.
    1.47 + *
    1.48 + * Subdirectories are not searched recursively, i.e., foo/"*" only
    1.49 + * looks for jar files in foo, not in foo/bar, foo/baz, etc.
    1.50 + *
    1.51 + * Expansion of wildcards is done early, prior to the invocation of a
    1.52 + * program's main method, rather than late, during the class-loading
    1.53 + * process itself.  Each element of the input class path containing a
    1.54 + * wildcard is replaced by the (possibly empty) sequence of elements
    1.55 + * generated by enumerating the jar files in the named directory.  If
    1.56 + * the directory foo contains a.jar, b.jar, and c.jar,
    1.57 + * e.g., then the class path foo/"*" is expanded into
    1.58 + * foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value
    1.59 + * of the system property java.class.path.
    1.60 + *
    1.61 + * The order in which the jar files in a directory are enumerated in
    1.62 + * the expanded class path is not specified and may vary from platform
    1.63 + * to platform and even from moment to moment on the same machine.  A
    1.64 + * well-constructed application should not depend upon any particular
    1.65 + * order.  If a specific order is required then the jar files can be
    1.66 + * enumerated explicitly in the class path.
    1.67 + *
    1.68 + * The CLASSPATH environment variable is not treated any differently
    1.69 + * from the -classpath (equiv. -cp) command-line option,
    1.70 + * i.e. wildcards are honored in all these cases.
    1.71 + *
    1.72 + * Class-path wildcards are not honored in the Class-Path jar-manifest
    1.73 + * header.
    1.74 + *
    1.75 + * Class-path wildcards are honored not only by the Java launcher but
    1.76 + * also by most other command-line tools that accept class paths, and
    1.77 + * in particular by javac and javadoc.
    1.78 + *
    1.79 + * Class-path wildcards are not honored in any other kind of path, and
    1.80 + * especially not in the bootstrap class path, which is a mere
    1.81 + * artifact of our implementation and not something that developers
    1.82 + * should use.
    1.83 + *
    1.84 + * Classpath wildcards are only expanded in the Java launcher code,
    1.85 + * supporting the use of wildcards on the command line and in the
    1.86 + * CLASSPATH environment variable.  We do not support the use of
    1.87 + * wildcards by applications that embed the JVM.
    1.88 + */
    1.89 +
    1.90 +#include <stddef.h>
    1.91 +#include <stdio.h>
    1.92 +#include <stdlib.h>
    1.93 +#include <string.h>
    1.94 +#include <sys/types.h>
    1.95 +#include "java.h"       /* Strictly for PATH_SEPARATOR/FILE_SEPARATOR */
    1.96 +#include "jli_util.h"
    1.97 +
    1.98 +#ifdef _WIN32
    1.99 +#include <windows.h>
   1.100 +#else /* Unix */
   1.101 +#include <unistd.h>
   1.102 +#include <dirent.h>
   1.103 +#endif /* Unix */
   1.104 +
   1.105 +static int
   1.106 +exists(const char* filename)
   1.107 +{
   1.108 +#ifdef _WIN32
   1.109 +    return _access(filename, 0) == 0;
   1.110 +#else
   1.111 +    return access(filename, F_OK) == 0;
   1.112 +#endif
   1.113 +}
   1.114 +
   1.115 +#define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_)))
   1.116 +
   1.117 +/*
   1.118 + * Wildcard directory iteration.
   1.119 + * WildcardIterator_for(wildcard) returns an iterator.
   1.120 + * Each call to that iterator's next() method returns the basename
   1.121 + * of an entry in the wildcard's directory.  The basename's memory
   1.122 + * belongs to the iterator.  The caller is responsible for prepending
   1.123 + * the directory name and file separator, if necessary.
   1.124 + * When done with the iterator, call the close method to clean up.
   1.125 + */
   1.126 +typedef struct WildcardIterator_* WildcardIterator;
   1.127 +
   1.128 +#ifdef _WIN32
   1.129 +struct WildcardIterator_
   1.130 +{
   1.131 +    HANDLE handle;
   1.132 +    char *firstFile; /* Stupid FindFirstFile...FindNextFile */
   1.133 +};
   1.134 +
   1.135 +static WildcardIterator
   1.136 +WildcardIterator_for(const char *wildcard)
   1.137 +{
   1.138 +    WIN32_FIND_DATA find_data;
   1.139 +    WildcardIterator it = NEW_(WildcardIterator);
   1.140 +    HANDLE handle = FindFirstFile(wildcard, &find_data);
   1.141 +    if (handle == INVALID_HANDLE_VALUE)
   1.142 +        return NULL;
   1.143 +    it->handle = handle;
   1.144 +    it->firstFile = find_data.cFileName;
   1.145 +    return it;
   1.146 +}
   1.147 +
   1.148 +static char *
   1.149 +WildcardIterator_next(WildcardIterator it)
   1.150 +{
   1.151 +    WIN32_FIND_DATA find_data;
   1.152 +    if (it->firstFile != NULL) {
   1.153 +        char *firstFile = it->firstFile;
   1.154 +        it->firstFile = NULL;
   1.155 +        return firstFile;
   1.156 +    }
   1.157 +    return FindNextFile(it->handle, &find_data)
   1.158 +        ? find_data.cFileName : NULL;
   1.159 +}
   1.160 +
   1.161 +static void
   1.162 +WildcardIterator_close(WildcardIterator it)
   1.163 +{
   1.164 +    if (it) {
   1.165 +        FindClose(it->handle);
   1.166 +        JLI_MemFree(it->firstFile);
   1.167 +        JLI_MemFree(it);
   1.168 +    }
   1.169 +}
   1.170 +
   1.171 +#else /* Unix */
   1.172 +struct WildcardIterator_
   1.173 +{
   1.174 +    DIR *dir;
   1.175 +};
   1.176 +
   1.177 +static WildcardIterator
   1.178 +WildcardIterator_for(const char *wildcard)
   1.179 +{
   1.180 +    DIR *dir;
   1.181 +    int wildlen = strlen(wildcard);
   1.182 +    if (wildlen < 2) {
   1.183 +        dir = opendir(".");
   1.184 +    } else {
   1.185 +        char *dirname = JLI_StringDup(wildcard);
   1.186 +        dirname[wildlen - 1] = '\0';
   1.187 +        dir = opendir(dirname);
   1.188 +        JLI_MemFree(dirname);
   1.189 +    }
   1.190 +    if (dir == NULL)
   1.191 +        return NULL;
   1.192 +    else {
   1.193 +        WildcardIterator it = NEW_(WildcardIterator);
   1.194 +        it->dir = dir;
   1.195 +        return it;
   1.196 +    }
   1.197 +}
   1.198 +
   1.199 +static char *
   1.200 +WildcardIterator_next(WildcardIterator it)
   1.201 +{
   1.202 +    struct dirent* dirp = readdir(it->dir);
   1.203 +    return dirp ? dirp->d_name : NULL;
   1.204 +}
   1.205 +
   1.206 +static void
   1.207 +WildcardIterator_close(WildcardIterator it)
   1.208 +{
   1.209 +    if (it) {
   1.210 +        closedir(it->dir);
   1.211 +        JLI_MemFree(it);
   1.212 +    }
   1.213 +}
   1.214 +#endif /* Unix */
   1.215 +
   1.216 +static int
   1.217 +equal(const char *s1, const char *s2)
   1.218 +{
   1.219 +    return strcmp(s1, s2) == 0;
   1.220 +}
   1.221 +
   1.222 +/*
   1.223 + * FileList ADT - a dynamic list of C filenames
   1.224 + */
   1.225 +struct FileList_
   1.226 +{
   1.227 +    char **files;
   1.228 +    int size;
   1.229 +    int capacity;
   1.230 +};
   1.231 +typedef struct FileList_ *FileList;
   1.232 +
   1.233 +static FileList
   1.234 +FileList_new(int capacity)
   1.235 +{
   1.236 +    FileList fl = NEW_(FileList);
   1.237 +    fl->capacity = capacity;
   1.238 +    fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0]));
   1.239 +    fl->size = 0;
   1.240 +    return fl;
   1.241 +}
   1.242 +
   1.243 +#ifdef DEBUG_WILDCARD
   1.244 +static void
   1.245 +FileList_print(FileList fl)
   1.246 +{
   1.247 +    int i;
   1.248 +    putchar('[');
   1.249 +    for (i = 0; i < fl->size; i++) {
   1.250 +        if (i > 0) printf(", ");
   1.251 +        printf("\"%s\"",fl->files[i]);
   1.252 +    }
   1.253 +    putchar(']');
   1.254 +}
   1.255 +#endif
   1.256 +
   1.257 +static void
   1.258 +FileList_free(FileList fl)
   1.259 +{
   1.260 +    if (fl) {
   1.261 +        if (fl->files) {
   1.262 +            int i;
   1.263 +            for (i = 0; i < fl->size; i++)
   1.264 +                JLI_MemFree(fl->files[i]);
   1.265 +            JLI_MemFree(fl->files);
   1.266 +        }
   1.267 +        JLI_MemFree(fl);
   1.268 +    }
   1.269 +}
   1.270 +
   1.271 +static void
   1.272 +FileList_ensureCapacity(FileList fl, int capacity)
   1.273 +{
   1.274 +    if (fl->capacity < capacity) {
   1.275 +        while (fl->capacity < capacity)
   1.276 +            fl->capacity *= 2;
   1.277 +        fl->files = JLI_MemRealloc(fl->files,
   1.278 +                               fl->capacity * sizeof(fl->files[0]));
   1.279 +    }
   1.280 +}
   1.281 +
   1.282 +static void
   1.283 +FileList_add(FileList fl, char *file)
   1.284 +{
   1.285 +    FileList_ensureCapacity(fl, fl->size+1);
   1.286 +    fl->files[fl->size++] = file;
   1.287 +}
   1.288 +
   1.289 +static void
   1.290 +FileList_addSubstring(FileList fl, const char *beg, int len)
   1.291 +{
   1.292 +    char *filename = (char *) JLI_MemAlloc(len+1);
   1.293 +    memcpy(filename, beg, len);
   1.294 +    filename[len] = '\0';
   1.295 +    FileList_ensureCapacity(fl, fl->size+1);
   1.296 +    fl->files[fl->size++] = filename;
   1.297 +}
   1.298 +
   1.299 +static char *
   1.300 +FileList_join(FileList fl, char sep)
   1.301 +{
   1.302 +    int i;
   1.303 +    int size;
   1.304 +    char *path;
   1.305 +    char *p;
   1.306 +    for (i = 0, size = 1; i < fl->size; i++)
   1.307 +        size += strlen(fl->files[i]) + 1;
   1.308 +
   1.309 +    path = JLI_MemAlloc(size);
   1.310 +
   1.311 +    for (i = 0, p = path; i < fl->size; i++) {
   1.312 +        int len = strlen(fl->files[i]);
   1.313 +        if (i > 0) *p++ = sep;
   1.314 +        memcpy(p, fl->files[i], len);
   1.315 +        p += len;
   1.316 +    }
   1.317 +    *p = '\0';
   1.318 +
   1.319 +    return path;
   1.320 +}
   1.321 +
   1.322 +static FileList
   1.323 +FileList_split(const char *path, char sep)
   1.324 +{
   1.325 +    const char *p, *q;
   1.326 +    int len = strlen(path);
   1.327 +    int count;
   1.328 +    FileList fl;
   1.329 +    for (count = 1, p = path; p < path + len; p++)
   1.330 +        count += (*p == sep);
   1.331 +    fl = FileList_new(count);
   1.332 +    for (p = path;;) {
   1.333 +        for (q = p; q <= path + len; q++) {
   1.334 +            if (*q == sep || *q == '\0') {
   1.335 +                FileList_addSubstring(fl, p, q - p);
   1.336 +                if (*q == '\0')
   1.337 +                    return fl;
   1.338 +                p = q + 1;
   1.339 +            }
   1.340 +        }
   1.341 +    }
   1.342 +}
   1.343 +
   1.344 +static int
   1.345 +isJarFileName(const char *filename)
   1.346 +{
   1.347 +    int len = strlen(filename);
   1.348 +    return (len >= 4) &&
   1.349 +        (filename[len - 4] == '.') &&
   1.350 +        (equal(filename + len - 3, "jar") ||
   1.351 +         equal(filename + len - 3, "JAR")) &&
   1.352 +        /* Paranoia: Maybe filename is "DIR:foo.jar" */
   1.353 +        (strchr(filename, PATH_SEPARATOR) == NULL);
   1.354 +}
   1.355 +
   1.356 +static char *
   1.357 +wildcardConcat(const char *wildcard, const char *basename)
   1.358 +{
   1.359 +    int wildlen = strlen(wildcard);
   1.360 +    int baselen = strlen(basename);
   1.361 +    char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
   1.362 +    /* Replace the trailing '*' with basename */
   1.363 +    memcpy(filename, wildcard, wildlen-1);
   1.364 +    memcpy(filename+wildlen-1, basename, baselen+1);
   1.365 +    return filename;
   1.366 +}
   1.367 +
   1.368 +static FileList
   1.369 +wildcardFileList(const char *wildcard)
   1.370 +{
   1.371 +    const char *basename;
   1.372 +    FileList fl = FileList_new(16);
   1.373 +    WildcardIterator it = WildcardIterator_for(wildcard);
   1.374 +    if (it == NULL)
   1.375 +        return NULL;
   1.376 +    while ((basename = WildcardIterator_next(it)) != NULL)
   1.377 +        if (isJarFileName(basename))
   1.378 +            FileList_add(fl, wildcardConcat(wildcard, basename));
   1.379 +    WildcardIterator_close(it);
   1.380 +    return fl;
   1.381 +}
   1.382 +
   1.383 +static int
   1.384 +isWildcard(const char *filename)
   1.385 +{
   1.386 +    int len = strlen(filename);
   1.387 +    return (len > 0) &&
   1.388 +        (filename[len - 1] == '*') &&
   1.389 +        (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
   1.390 +        (! exists(filename));
   1.391 +}
   1.392 +
   1.393 +static void
   1.394 +FileList_expandWildcards(FileList fl)
   1.395 +{
   1.396 +    int i, j;
   1.397 +    for (i = 0; i < fl->size; i++) {
   1.398 +        if (isWildcard(fl->files[i])) {
   1.399 +            FileList expanded = wildcardFileList(fl->files[i]);
   1.400 +            if (expanded != NULL && expanded->size > 0) {
   1.401 +                JLI_MemFree(fl->files[i]);
   1.402 +                FileList_ensureCapacity(fl, fl->size + expanded->size);
   1.403 +                for (j = fl->size - 1; j >= i+1; j--)
   1.404 +                    fl->files[j+expanded->size-1] = fl->files[j];
   1.405 +                for (j = 0; j < expanded->size; j++)
   1.406 +                    fl->files[i+j] = expanded->files[j];
   1.407 +                i += expanded->size - 1;
   1.408 +                fl->size += expanded->size - 1;
   1.409 +                /* fl expropriates expanded's elements. */
   1.410 +                expanded->size = 0;
   1.411 +            }
   1.412 +            FileList_free(expanded);
   1.413 +        }
   1.414 +    }
   1.415 +}
   1.416 +
   1.417 +const char *
   1.418 +JLI_WildcardExpandClasspath(const char *classpath)
   1.419 +{
   1.420 +    char *expanded;
   1.421 +    FileList fl;
   1.422 +
   1.423 +    if (strchr(classpath, '*') == NULL)
   1.424 +        return classpath;
   1.425 +    fl = FileList_split(classpath, PATH_SEPARATOR);
   1.426 +    FileList_expandWildcards(fl);
   1.427 +    expanded = FileList_join(fl, PATH_SEPARATOR);
   1.428 +    FileList_free(fl);
   1.429 +    if (getenv("_JAVA_LAUNCHER_DEBUG") != 0)
   1.430 +        printf("Expanded wildcards:\n"
   1.431 +               "    before: \"%s\"\n"
   1.432 +               "    after : \"%s\"\n",
   1.433 +               classpath, expanded);
   1.434 +    return expanded;
   1.435 +}
   1.436 +
   1.437 +#ifdef DEBUG_WILDCARD
   1.438 +static void
   1.439 +wildcardExpandArgv(const char ***argv)
   1.440 +{
   1.441 +    int i;
   1.442 +    for (i = 0; (*argv)[i]; i++) {
   1.443 +        if (equal((*argv)[i], "-cp") ||
   1.444 +            equal((*argv)[i], "-classpath")) {
   1.445 +            i++;
   1.446 +            (*argv)[i] = wildcardExpandClasspath((*argv)[i]);
   1.447 +        }
   1.448 +    }
   1.449 +}
   1.450 +
   1.451 +static void
   1.452 +debugPrintArgv(char *argv[])
   1.453 +{
   1.454 +    int i;
   1.455 +    putchar('[');
   1.456 +    for (i = 0; argv[i]; i++) {
   1.457 +        if (i > 0) printf(", ");
   1.458 +        printf("\"%s\"", argv[i]);
   1.459 +    }
   1.460 +    printf("]\n");
   1.461 +}
   1.462 +
   1.463 +int
   1.464 +main(int argc, char *argv[])
   1.465 +{
   1.466 +    argv[0] = "java";
   1.467 +    wildcardExpandArgv((const char***)&argv);
   1.468 +    debugPrintArgv(argv);
   1.469 +    /* execvp("java", argv); */
   1.470 +    return 0;
   1.471 +}
   1.472 +#endif /* DEBUG_WILDCARD */
   1.473 +
   1.474 +/* Cute little perl prototype implementation....
   1.475 +
   1.476 +my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":";
   1.477 +
   1.478 +sub expand($) {
   1.479 +  opendir DIR, $_[0] or return $_[0];
   1.480 +  join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR;
   1.481 +}
   1.482 +
   1.483 +sub munge($) {
   1.484 +  join $sep,
   1.485 +    map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0];
   1.486 +}
   1.487 +
   1.488 +for (my $i = 0; $i < @ARGV - 1; $i++) {
   1.489 +  $ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/;
   1.490 +}
   1.491 +
   1.492 +$ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH};
   1.493 +@ARGV = ("java", @ARGV);
   1.494 +print "@ARGV\n";
   1.495 +exec @ARGV;
   1.496 +
   1.497 +*/

mercurial