《jdk8u源码分析》9.1.JLI_WildcardExpandClasspath

src/share/bin/wildcard.c::JLI_WildcardExpandClasspath

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

	//不包含通配符'*'直接返回字符串
    if (JLI_StrChr(classpath, '*') == NULL)
        return classpath;
    //通过路径分隔符 ':'(mac) | ';'(windows) 分割classpath,储存在FileList的files字符指针中
    fl = FileList_split(classpath, PATH_SEPARATOR);
    //展开通配符,获取通配符匹配的所有jar完整路径
    FileList_expandWildcards(fl);
    //拼接fl.files中的所有jar完整路径,以路径分隔符分割,并保存至expanded中返回
    expanded = FileList_join(fl, PATH_SEPARATOR);
    //释放fl内存
    FileList_free(fl);
    //Expanded wildcards:
    //    before: C:\Program Files\Java\jre1.8.0_172\lib\*
    //    after : C:\Program Files\Java\jre1.8.0_172\lib\charsets.jar;C:\Program Files\Java\jre1.8.0_172\lib\deploy.jar;...
    if (getenv(JLDEBUG_ENV_ENTRY) != 0)
        printf("Expanded wildcards:\n"
               "    before: \"%s\"\n"
               "    after : \"%s\"\n",
               classpath, expanded);
    return expanded;
}

src/share/bin/wildcard.c::FileList_

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

src/share/bin/wildcard.c::FileList_split

static FileList
FileList_split(const char *path, char sep)
{
    const char *p, *q;
    int len = (int)JLI_StrLen(path);
    int count;
    FileList fl;
    //FileList->capacity = 统计路径分隔符数量 + 1;
    for (count = 1, p = path; p < path + len; p++)
        count += (*p == sep);
    //初始化FileList
    fl = FileList_new(count);
    //
    for (p = path;;) {
        for (q = p; q <= path + len; q++) {
        	//q指针移动遇到分隔符或者字符串结束,将 q - p 之间的字符串储存在FileList中
            if (*q == sep || *q == '\0') {
            	//字符指针指向字符串首地址,q 与 p 指向同一个字符串 path
            	//q - p 就是两个地址指向的内存地址的差值,即两个子串长度的差值
                FileList_addSubstring(fl, p, q - p);
                //遇到结束符'\0'说明已经遍历完整个path,直接返回fl
                if (*q == '\0')
                    return fl;
                //如果未遍历完,将p指向q+1,即分割符以后,继续遍历剩余的字符串
                p = q + 1;
            }
        }
    }
}

src/share/bin/wildcard.c::FileList_new

static FileList
FileList_new(int capacity)
{
	//根据给定容量初始化FileList
    FileList fl = NEW_(FileList);
    fl->capacity = capacity;
    fl->files = (char **) JLI_MemAlloc(capacity * sizeof(fl->files[0]));
    fl->size = 0;
    return fl;
}

src/share/bin/wildcard.c::FileList_addSubstring

static void
FileList_addSubstring(FileList fl, const char *beg, int len)
{
	//将新增的jar地址储存在filename中,并分配内存,加1是为'\0'
    char *filename = (char *) JLI_MemAlloc(len+1);
    memcpy(filename, beg, len);
    filename[len] = '\0';
    //检查容量是否足够,不够则扩容为原来的2倍
    FileList_ensureCapacity(fl, fl->size+1);
    //将filename存入到files指针中
    fl->files[fl->size++] = filename;
}

src/share/bin/wildcard.c::FileList_ensureCapacity

static void
FileList_ensureCapacity(FileList fl, int capacity)
{
	//如果需求的容量超出当前FileList的最大容量,扩容至当前容量的2倍
    if (fl->capacity < capacity) {
        while (fl->capacity < capacity)
            fl->capacity *= 2;
        //重新分配内存
        fl->files = JLI_MemRealloc(fl->files,
                               fl->capacity * sizeof(fl->files[0]));
    }
}

src/share/bin/wildcard.c::FileList_expandWildcards

static void
FileList_expandWildcards(FileList fl)
{
    int i, j;
    for (i = 0; i < fl->size; i++) {
    	//如果jar地址中包含通配符'*',就展开路径,获取所有匹配的jar包完整路径替换
        if (isWildcard(fl->files[i])) {
        	//展开通配符,以所有匹配的文件地址替换
            FileList expanded = wildcardFileList(fl->files[i]);
            if (expanded != NULL && expanded->size > 0) {
            	//释放存储当前包含通配符地址的字符变量fl->files[i]
                JLI_MemFree(fl->files[i]);
                FileList_ensureCapacity(fl, fl->size + expanded->size);
                //将当前包含通配符地址后的指针向后移动expanded->size-1个单位(i释放掉所以减1)
                for (j = fl->size - 1; j >= i+1; j--)
                    fl->files[j+expanded->size-1] = fl->files[j];
                //从i处开始插入expanded包含的所有files
                for (j = 0; j < expanded->size; j++)
                    fl->files[i+j] = expanded->files[j];
                //更新i变量值及fl->size
                i += expanded->size - 1;
                fl->size += expanded->size - 1;
                /* fl expropriates expanded's elements. */
                //expanded->size置0
                expanded->size = 0;
            }
            //释放expanded
            FileList_free(expanded);
        }
    }
}

src/share/bin/wildcard.c::isWildcard

static int
isWildcard(const char *filename)
{
    int len = (int)JLI_StrLen(filename);
    //1.文件地址不为空
    //2.判断文件地址包含通配符'*'
    //3.文件地址长度为1,或者倒数第二个字符为文件分隔符
    //4.文件不存在
    return (len > 0) &&
        (filename[len - 1] == '*') &&
        (len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
        (! exists(filename));
}

src/windows/bin/java_md.h

//判断字符是否为文件分隔符
#define IS_FILE_SEPARATOR(c) ((c) == '\\' || (c) == '/')

src/solaris/bin/java_md.h

#define IS_FILE_SEPARATOR(c) ((c) == '/')

src/share/bin/wildcard.c::exists

static int
exists(const char* filename)
{
	//判断文件访问权限
	//#define R_OK 4 /* Test for read permission. */只判断是否有读权限
	//#define W_OK 2 /* Test for write permission. */只判断是否有写权限
	//#define X_OK 1 /* Test for execute permission. */判断是否有执行权限
	//#define F_OK 0 /* Test for existence. */只判断是否存在
	//0 - YES; 1 - NO
#ifdef _WIN32
    return _access(filename, 0) == 0;
#else
    return access(filename, F_OK) == 0;
#endif
}

src/share/bin/wildcard.c::wildcardFileList

static FileList
wildcardFileList(const char *wildcard)
{
    const char *basename;
    //新建FileList对象fl
    FileList fl = FileList_new(16);
    //给定包含通配符的jar路径,创建迭代器
    WildcardIterator it = WildcardIterator_for(wildcard);

    if (it == NULL)
    {
        FileList_free(fl);
        return NULL;
    }
	
	//依次获取匹配的文件地址,判断是否以.jar | .JAR 结尾
	//如果是,将wildcard通配符之前的目录和匹配到的文件名拼接存入FileList->files中
    while ((basename = WildcardIterator_next(it)) != NULL)
        if (isJarFileName(basename))
            FileList_add(fl, wildcardConcat(wildcard, basename));
    WildcardIterator_close(it);
    return fl;
}

src/share/bin/wildcard.c::FileList_free

static void
FileList_free(FileList fl)
{
    if (fl) {
    	//先释放每个files指针再释放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);
    }
}

src/share/bin/wildcard.c::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);
    //获取第一个匹配的文件,如果存在,将结果放入find_data中
    HANDLE handle = FindFirstFile(wildcard, &find_data);
    //如果没有匹配的文件直接返回NULL
    if (handle == INVALID_HANDLE_VALUE) {
        JLI_MemFree(it);
        return NULL;
    }
    //======================================================
    //e.g.:
    //wildcard:C:\Program Files\Java\jre1.8.0_172\lib\*.jar
    //basename:charsets.jar
    //basename:deploy.jar
    //basename:javaws.jar
    //basename:jce.jar
    //basename:jfr.jar
    //basename:jfxswt.jar
    //basename:jsse.jar
    //basename:management-agent.jar
    //basename:plugin.jar
    //basename:resources.jar
    //basename:rt.jar
    //======================================================
    //获取成功,返回迭代器it
    it->handle = handle;
    //将第一个文件名存入it->firstFile中
    it->firstFile = find_data.cFileName;
    return it;
}

static char *
WildcardIterator_next(WildcardIterator it)
{
	//获取第一个匹配的文件,并返回,将迭代器的firstFile置空
    if (it->firstFile != NULL) {
        char *firstFile = it->firstFile;
        it->firstFile = NULL;
        return firstFile;
    }
    //获取下一个匹配的文件,如果没有跟多文件,返回NULL
    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 */

src/share/bin/wildcard.c::FileList_add

static void
FileList_add(FileList fl, char *file)
{
	//判断容量是否足够存储,如果不够则扩容至当前容量的2倍
    FileList_ensureCapacity(fl, fl->size+1);
    //将jar文件名添加到files指针中
    fl->files[fl->size++] = file;
}

src/share/bin/wildcard.c::isJarFileName

static int
isJarFileName(const char *filename)
{
    int len = (int)JLI_StrLen(filename);
    //1. 文件名长度大于等于4
    //2. 以 jar | JAR 结尾
    //3. 不包含路径分割符:':'(mac) | ';'(windows)
    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);
}

src/share/bin/wildcard.c::wildcardConcat

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 */
    //移除wildcard最后一个字符,拷贝到filename中
    memcpy(filename, wildcard, wildlen-1);
    //继续拷贝basename到filename中
    memcpy(filename+wildlen-1, basename, baselen+1);
    return filename;
}

src/share/bin/wildcard.c::FileList_join

static char *
FileList_join(FileList fl, char sep)
{
    int i;
    int size;
    char *path;
    char *p;
    //计算jar文件路径列表拼接需要分配的内存大小
    for (i = 0, size = 1; i < fl->size; i++)
        size += (int)JLI_StrLen(fl->files[i]) + 1;//1为分隔符的长度

    path = JLI_MemAlloc(size);
	
	//将jar文件路径拼接到字符指针path中
    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',释放p指针
    *p = '\0';

    return path;
}

猜你喜欢

转载自blog.csdn.net/weixin_37477523/article/details/88364102