alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (wildcard.c)

This example Java source code file (wildcard.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

filelist, filelist_ensurecapacity, filelist_free, filelist_new, jli_memalloc, jli_memfree, new_, null, path_separator, unix, wildcarditerator, wildcarditerator_close, wildcarditerator_for, wildcarditerator_next

The wildcard.c Java example source code

/*
 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * Class-Path Wildcards
 *
 * The syntax for wildcards is a single asterisk. The class path
 * foo/"*", e.g., loads all jar files in the directory named foo.
 * (This requires careful quotation when used in shell scripts.)
 *
 * Only files whose names end in .jar or .JAR are matched.
 * Files whose names end in .zip, or which have a particular
 * magic number, regardless of filename extension, are not
 * matched.
 *
 * Files are considered regardless of whether or not they are
 * "hidden" in the UNIX sense, i.e., have names beginning with '.'.
 *
 * A wildcard only matches jar files, not class files in the same
 * directory.  If you want to load both class files and jar files from
 * a single directory foo then you can say foo:foo/"*", or foo/"*":foo
 * if you want the jar files to take precedence.
 *
 * Subdirectories are not searched recursively, i.e., foo/"*" only
 * looks for jar files in foo, not in foo/bar, foo/baz, etc.
 *
 * Expansion of wildcards is done early, prior to the invocation of a
 * program's main method, rather than late, during the class-loading
 * process itself.  Each element of the input class path containing a
 * wildcard is replaced by the (possibly empty) sequence of elements
 * generated by enumerating the jar files in the named directory.  If
 * the directory foo contains a.jar, b.jar, and c.jar,
 * e.g., then the class path foo/"*" is expanded into
 * foo/a.jar:foo/b.jar:foo/c.jar, and that string would be the value
 * of the system property java.class.path.
 *
 * The order in which the jar files in a directory are enumerated in
 * the expanded class path is not specified and may vary from platform
 * to platform and even from moment to moment on the same machine.  A
 * well-constructed application should not depend upon any particular
 * order.  If a specific order is required then the jar files can be
 * enumerated explicitly in the class path.
 *
 * The CLASSPATH environment variable is not treated any differently
 * from the -classpath (equiv. -cp) command-line option,
 * i.e. wildcards are honored in all these cases.
 *
 * Class-path wildcards are not honored in the Class-Path jar-manifest
 * header.
 *
 * Class-path wildcards are honored not only by the Java launcher but
 * also by most other command-line tools that accept class paths, and
 * in particular by javac and javadoc.
 *
 * Class-path wildcards are not honored in any other kind of path, and
 * especially not in the bootstrap class path, which is a mere
 * artifact of our implementation and not something that developers
 * should use.
 *
 * Classpath wildcards are only expanded in the Java launcher code,
 * supporting the use of wildcards on the command line and in the
 * CLASSPATH environment variable.  We do not support the use of
 * wildcards by applications that embed the JVM.
 */

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "java.h"       /* Strictly for PATH_SEPARATOR/FILE_SEPARATOR */
#include "jli_util.h"

#ifdef _WIN32
#include <windows.h>
#else /* Unix */
#include <unistd.h>
#include <dirent.h>
#endif /* Unix */

static int
exists(const char* filename)
{
#ifdef _WIN32
    return _access(filename, 0) == 0;
#else
    return access(filename, F_OK) == 0;
#endif
}

#define NEW_(TYPE) ((TYPE) JLI_MemAlloc(sizeof(struct TYPE##_)))

/*
 * Wildcard directory iteration.
 * WildcardIterator_for(wildcard) returns an iterator.
 * Each call to that iterator's next() method returns the basename
 * of an entry in the wildcard's directory.  The basename's memory
 * belongs to the iterator.  The caller is responsible for prepending
 * the directory name and file separator, if necessary.
 * When done with the iterator, call the close method to clean up.
 */
typedef struct WildcardIterator_* WildcardIterator;

#ifdef _WIN32
struct WildcardIterator_
{
    HANDLE handle;
    char *firstFile; /* Stupid FindFirstFile...FindNextFile */
};
// since this is used repeatedly we keep it here.
static WIN32_FIND_DATA find_data;
static WildcardIterator
WildcardIterator_for(const char *wildcard)
{
    WildcardIterator it = NEW_(WildcardIterator);
    HANDLE handle = FindFirstFile(wildcard, &find_data);
    if (handle == INVALID_HANDLE_VALUE) {
        JLI_MemFree(it);
        return NULL;
    }
    it->handle = handle;
    it->firstFile = find_data.cFileName;
    return it;
}

static char *
WildcardIterator_next(WildcardIterator it)
{
    if (it->firstFile != NULL) {
        char *firstFile = it->firstFile;
        it->firstFile = NULL;
        return firstFile;
    }
    return FindNextFile(it->handle, &find_data)
        ? find_data.cFileName : NULL;
}

static void
WildcardIterator_close(WildcardIterator it)
{
    if (it) {
        FindClose(it->handle);
        JLI_MemFree(it->firstFile);
        JLI_MemFree(it);
    }
}

#else /* Unix */
struct WildcardIterator_
{
    DIR *dir;
};

static WildcardIterator
WildcardIterator_for(const char *wildcard)
{
    DIR *dir;
    int wildlen = JLI_StrLen(wildcard);
    if (wildlen < 2) {
        dir = opendir(".");
    } else {
        char *dirname = JLI_StringDup(wildcard);
        dirname[wildlen - 1] = '\0';
        dir = opendir(dirname);
        JLI_MemFree(dirname);
    }
    if (dir == NULL)
        return NULL;
    else {
        WildcardIterator it = NEW_(WildcardIterator);
        it->dir = dir;
        return it;
    }
}

static char *
WildcardIterator_next(WildcardIterator it)
{
    struct dirent* dirp = readdir(it->dir);
    return dirp ? dirp->d_name : NULL;
}

static void
WildcardIterator_close(WildcardIterator it)
{
    if (it) {
        closedir(it->dir);
        JLI_MemFree(it);
    }
}
#endif /* Unix */

static int
equal(const char *s1, const char *s2)
{
    return JLI_StrCmp(s1, s2) == 0;
}

/*
 * FileList ADT - a dynamic list of C filenames
 */
struct FileList_
{
    char **files;
    int size;
    int capacity;
};
typedef struct FileList_ *FileList;

static FileList
FileList_new(int capacity)
{
    FileList fl = NEW_(FileList);
    fl->capacity = capacity;
    fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0]));
    fl->size = 0;
    return fl;
}



static void
FileList_free(FileList fl)
{
    if (fl) {
        if (fl->files) {
            int i;
            for (i = 0; i < fl->size; i++)
                JLI_MemFree(fl->files[i]);
            JLI_MemFree(fl->files);
        }
        JLI_MemFree(fl);
    }
}

static void
FileList_ensureCapacity(FileList fl, int capacity)
{
    if (fl->capacity < capacity) {
        while (fl->capacity < capacity)
            fl->capacity *= 2;
        fl->files = JLI_MemRealloc(fl->files,
                               fl->capacity * sizeof(fl->files[0]));
    }
}

static void
FileList_add(FileList fl, char *file)
{
    FileList_ensureCapacity(fl, fl->size+1);
    fl->files[fl->size++] = file;
}

static void
FileList_addSubstring(FileList fl, const char *beg, int len)
{
    char *filename = (char *) JLI_MemAlloc(len+1);
    memcpy(filename, beg, len);
    filename[len] = '\0';
    FileList_ensureCapacity(fl, fl->size+1);
    fl->files[fl->size++] = filename;
}

static char *
FileList_join(FileList fl, char sep)
{
    int i;
    int size;
    char *path;
    char *p;
    for (i = 0, size = 1; i < fl->size; i++)
        size += (int)JLI_StrLen(fl->files[i]) + 1;

    path = JLI_MemAlloc(size);

    for (i = 0, p = path; i < fl->size; i++) {
        int len = (int)JLI_StrLen(fl->files[i]);
        if (i > 0) *p++ = sep;
        memcpy(p, fl->files[i], len);
        p += len;
    }
    *p = '\0';

    return path;
}

static FileList
FileList_split(const char *path, char sep)
{
    const char *p, *q;
    int len = (int)JLI_StrLen(path);
    int count;
    FileList fl;
    for (count = 1, p = path; p < path + len; p++)
        count += (*p == sep);
    fl = FileList_new(count);
    for (p = path;;) {
        for (q = p; q <= path + len; q++) {
            if (*q == sep || *q == '\0') {
                FileList_addSubstring(fl, p, q - p);
                if (*q == '\0')
                    return fl;
                p = q + 1;
            }
        }
    }
}

static int
isJarFileName(const char *filename)
{
    int len = (int)JLI_StrLen(filename);
    return (len >= 4) &&
        (filename[len - 4] == '.') &&
        (equal(filename + len - 3, "jar") ||
         equal(filename + len - 3, "JAR")) &&
        /* Paranoia: Maybe filename is "DIR:foo.jar" */
        (JLI_StrChr(filename, PATH_SEPARATOR) == NULL);
}

static char *
wildcardConcat(const char *wildcard, const char *basename)
{
    int wildlen = (int)JLI_StrLen(wildcard);
    int baselen = (int)JLI_StrLen(basename);
    char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
    /* Replace the trailing '*' with basename */
    memcpy(filename, wildcard, wildlen-1);
    memcpy(filename+wildlen-1, basename, baselen+1);
    return filename;
}

static FileList
wildcardFileList(const char *wildcard)
{
    const char *basename;
    FileList fl = FileList_new(16);
    WildcardIterator it = WildcardIterator_for(wildcard);

    if (it == NULL)
    {
        FileList_free(fl);
        return NULL;
    }

    while ((basename = WildcardIterator_next(it)) != NULL)
        if (isJarFileName(basename))
            FileList_add(fl, wildcardConcat(wildcard, basename));
    WildcardIterator_close(it);
    return fl;
}

static int
isWildcard(const char *filename)
{
    int len = (int)JLI_StrLen(filename);
    return (len > 0) &&
        (filename[len - 1] == '*') &&
        (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
        (! exists(filename));
}

static void
FileList_expandWildcards(FileList fl)
{
    int i, j;
    for (i = 0; i < fl->size; i++) {
        if (isWildcard(fl->files[i])) {
            FileList expanded = wildcardFileList(fl->files[i]);
            if (expanded != NULL && expanded->size > 0) {
                JLI_MemFree(fl->files[i]);
                FileList_ensureCapacity(fl, fl->size + expanded->size);
                for (j = fl->size - 1; j >= i+1; j--)
                    fl->files[j+expanded->size-1] = fl->files[j];
                for (j = 0; j < expanded->size; j++)
                    fl->files[i+j] = expanded->files[j];
                i += expanded->size - 1;
                fl->size += expanded->size - 1;
                /* fl expropriates expanded's elements. */
                expanded->size = 0;
            }
            FileList_free(expanded);
        }
    }
}

const char *
JLI_WildcardExpandClasspath(const char *classpath)
{
    char *expanded;
    FileList fl;

    if (JLI_StrChr(classpath, '*') == NULL)
        return classpath;
    fl = FileList_split(classpath, PATH_SEPARATOR);
    FileList_expandWildcards(fl);
    expanded = FileList_join(fl, PATH_SEPARATOR);
    FileList_free(fl);
    if (getenv(JLDEBUG_ENV_ENTRY) != 0)
        printf("Expanded wildcards:\n"
               "    before: \"%s\"\n"
               "    after : \"%s\"\n",
               classpath, expanded);
    return expanded;
}

#ifdef DEBUG_WILDCARD
static void
FileList_print(FileList fl)
{
    int i;
    putchar('[');
    for (i = 0; i < fl->size; i++) {
        if (i > 0) printf(", ");
        printf("\"%s\"",fl->files[i]);
    }
    putchar(']');
}

static void
wildcardExpandArgv(const char ***argv)
{
    int i;
    for (i = 0; (*argv)[i]; i++) {
        if (equal((*argv)[i], "-cp") ||
            equal((*argv)[i], "-classpath")) {
            i++;
            (*argv)[i] = wildcardExpandClasspath((*argv)[i]);
        }
    }
}

static void
debugPrintArgv(char *argv[])
{
    int i;
    putchar('[');
    for (i = 0; argv[i]; i++) {
        if (i > 0) printf(", ");
        printf("\"%s\"", argv[i]);
    }
    printf("]\n");
}

int
main(int argc, char *argv[])
{
    argv[0] = "java";
    wildcardExpandArgv((const char***)&argv);
    debugPrintArgv(argv);
    /* execvp("java", argv); */
    return 0;
}
#endif /* DEBUG_WILDCARD */

/* Cute little perl prototype implementation....

my $sep = ($^O =~ /^(Windows|cygwin)/) ? ";" : ":";

sub expand($) {
  opendir DIR, $_[0] or return $_[0];
  join $sep, map {"$_[0]/$_"} grep {/\.(jar|JAR)$/} readdir DIR;
}

sub munge($) {
  join $sep,
    map {(! -r $_ and s/[\/\\]+\*$//) ? expand $_ : $_} split $sep, $_[0];
}

for (my $i = 0; $i < @ARGV - 1; $i++) {
  $ARGV[$i+1] = munge $ARGV[$i+1] if $ARGV[$i] =~ /^-c(p|lasspath)$/;
}

$ENV{CLASSPATH} = munge $ENV{CLASSPATH} if exists $ENV{CLASSPATH};
@ARGV = ("java", @ARGV);
print "@ARGV\n";
exec @ARGV;

*/

Other Java examples (source code examples)

Here is a short list of links related to this Java wildcard.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.