📄 glob.c
字号:
#ifdef WINDOWS32 if (home_dir == NULL || home_dir[0] == '\0') home_dir = "c:/users/default"; /* poor default */#else if (home_dir == NULL || home_dir[0] == '\0') { int success;#if defined HAVE_GETLOGIN_R || defined _LIBC extern int getlogin_r __P((char *, size_t)); size_t buflen = sysconf(_SC_LOGIN_NAME_MAX) + 1; char *name; if (buflen == 0) /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try a moderate value. */ buflen = 16; name = (char *) __alloca(buflen); success = getlogin_r(name, buflen) >= 0;#else/* extern char *getlogin __P (); */ char *name; success = (name = getlogin()) != NULL;#endif if (success) {#if defined HAVE_GETPWNAM_R || defined _LIBC size_t pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwtmpbuf; struct passwd pwbuf, *p; pwtmpbuf = (char *) __alloca(pwbuflen); success = (__getpwnam_r(name, &pwbuf, pwtmpbuf, pwbuflen, &p) >= 0);#else struct passwd *p = getpwnam(name); success = p != NULL;#endif if (success) home_dir = p->pw_dir; } } if (home_dir == NULL || home_dir[0] == '\0') home_dir = (char *) "~"; /* No luck. */#endif /* WINDOWS32 */#endif /* Now construct the full directory. */ if (dirname[1] == '\0') dirname = home_dir; else { char *newp; size_t home_len = strlen(home_dir); newp = (char *) __alloca(home_len + dirlen);#ifdef HAVE_MEMPCPY mempcpy(mempcpy(newp, home_dir, home_len), &dirname[1], dirlen);#else memcpy(newp, home_dir, home_len); memcpy(&newp[home_len], &dirname[1], dirlen);#endif dirname = newp; } }#if !defined _AMIGA && !defined WINDOWS32 else { char *end_name = strchr(dirname, '/'); char *user_name; char *home_dir; if (end_name == NULL) user_name = dirname + 1; else { user_name = (char *) __alloca(end_name - dirname);#ifdef HAVE_MEMPCPY *((char *) mempcpy(user_name, dirname + 1, end_name - dirname)) = '\0';#else memcpy(user_name, dirname + 1, end_name - dirname); user_name[end_name - dirname - 1] = '\0';#endif } /* Look up specific user's home directory. */ {#if defined HAVE_GETPWNAM_R || defined _LIBC size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwtmpbuf = (char *) __alloca(buflen); struct passwd pwbuf, *p; if (__getpwnam_r(user_name, &pwbuf, pwtmpbuf, buflen, &p) >= 0) home_dir = p->pw_dir; else home_dir = NULL;#else struct passwd *p = getpwnam(user_name); if (p != NULL) home_dir = p->pw_dir; else home_dir = NULL;#endif } /* If we found a home directory use this. */ if (home_dir != NULL) { char *newp; size_t home_len = strlen(home_dir); size_t rest_len = end_name == NULL ? 0 : strlen(end_name); newp = (char *) __alloca(home_len + rest_len + 1);#ifdef HAVE_MEMPCPY *((char *) mempcpy(mempcpy(newp, home_dir, home_len), end_name, rest_len)) = '\0';#else memcpy(newp, home_dir, home_len); memcpy(&newp[home_len], end_name, rest_len); newp[home_len + rest_len] = '\0';#endif dirname = newp; } }#endif /* Not Amiga && not WINDOWS32. */ }#endif /* Not VMS. */ if (__glob_pattern_p(dirname, !(flags & GLOB_NOESCAPE))) { /* The directory name contains metacharacters, so we have to glob for the directory, and then glob for the pattern in each directory found. */ glob_t dirs; register int i; status = glob(dirname, ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) | GLOB_NOSORT | GLOB_ONLYDIR), errfunc, &dirs); if (status != 0) return status; /* We have successfully globbed the preceding directory name. For each name we found, call glob_in_dir on it and FILENAME, appending the results to PGLOB. */ for (i = 0; i < dirs.gl_pathc; ++i) { int oldcount; oldcount = pglob->gl_pathc; status = glob_in_dir(filename, dirs.gl_pathv[i], ((flags | GLOB_APPEND) & ~(GLOB_NOCHECK | GLOB_ERR)), errfunc, pglob); if (status == GLOB_NOMATCH) /* No matches in this directory. Try the next. */ continue; if (status != 0) { globfree(&dirs); globfree(pglob); return status; } /* Stick the directory on the front of each name. */ if (prefix_array(dirs.gl_pathv[i], &pglob->gl_pathv[oldcount], pglob->gl_pathc - oldcount)) { globfree(&dirs); globfree(pglob); return GLOB_NOSPACE; } } flags |= GLOB_MAGCHAR; if (pglob->gl_pathc == oldcount) /* No matches. */ if (flags & GLOB_NOCHECK) { size_t len = strlen(pattern) + 1; char *patcopy = (char *) malloc(len); if (patcopy == NULL) return GLOB_NOSPACE; memcpy(patcopy, pattern, len); pglob->gl_pathv = (char **) realloc(pglob->gl_pathv, (pglob->gl_pathc + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + 1 + 1) * sizeof(char *)); if (pglob->gl_pathv == NULL) { free(patcopy); return GLOB_NOSPACE; } if (flags & GLOB_DOOFFS) while (pglob->gl_pathc < pglob->gl_offs) pglob->gl_pathv[pglob->gl_pathc++] = NULL; pglob->gl_pathv[pglob->gl_pathc++] = patcopy; pglob->gl_pathv[pglob->gl_pathc] = NULL; pglob->gl_flags = flags; } else return GLOB_NOMATCH; } else { status = glob_in_dir(filename, dirname, flags, errfunc, pglob); if (status != 0) return status; if (dirlen > 0) { /* Stick the directory on the front of each name. */ if (prefix_array(dirname, &pglob->gl_pathv[oldcount], pglob->gl_pathc - oldcount)) { globfree(pglob); return GLOB_NOSPACE; } } } if (flags & GLOB_MARK) { /* Append slashes to directory names. */ int i; struct stat st; for (i = oldcount; i < pglob->gl_pathc; ++i) if (((flags & GLOB_ALTDIRFUNC) ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st) : __stat(pglob->gl_pathv[i], &st)) == 0 && S_ISDIR(st.st_mode)) { size_t len = strlen(pglob->gl_pathv[i]) + 2; char *new = realloc(pglob->gl_pathv[i], len); if (new == NULL) { globfree(pglob); return GLOB_NOSPACE; } strcpy(&new[len - 2], "/"); pglob->gl_pathv[i] = new; } } if (!(flags & GLOB_NOSORT)) /* Sort the vector. */ qsort((__ptr_t) & pglob->gl_pathv[oldcount], pglob->gl_pathc - oldcount, sizeof(char *), collated_compare); return 0;}/* Free storage allocated in PGLOB by a previous `glob' call. */void globfree(pglob) register glob_t *pglob;{ if (pglob->gl_pathv != NULL) { register int i; for (i = 0; i < pglob->gl_pathc; ++i) if (pglob->gl_pathv[i] != NULL) free((__ptr_t) pglob->gl_pathv[i]); free((__ptr_t) pglob->gl_pathv); }}/* Do a collated comparison of A and B. */static int collated_compare(a, b) const __ptr_t a; const __ptr_t b;{ const char *const s1 = *(const char *const *const) a; const char *const s2 = *(const char *const *const) b; if (s1 == s2) return 0; if (s1 == NULL) return 1; if (s2 == NULL) return -1; return strcoll(s1, s2);}/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's elements in place. Return nonzero if out of memory, zero if successful. A slash is inserted between DIRNAME and each elt of ARRAY, unless DIRNAME is just "/". Each old element of ARRAY is freed. */static int prefix_array(dirname, array, n) const char *dirname; char **array; size_t n;{ register size_t i; size_t dirlen = strlen(dirname); if (dirlen == 1 && dirname[0] == '/') /* DIRNAME is just "/", so normal prepending would get us "//foo". We want "/foo" instead, so don't prepend any chars from DIRNAME. */ dirlen = 0; for (i = 0; i < n; ++i) { size_t eltlen = strlen(array[i]) + 1; char *new = (char *) malloc(dirlen + 1 + eltlen); if (new == NULL) { while (i > 0) free((__ptr_t) array[--i]); return 1; }#ifdef HAVE_MEMPCPY { char *endp = (char *) mempcpy(new, dirname, dirlen); *endp++ = '/'; mempcpy(endp, array[i], eltlen); }#else memcpy(new, dirname, dirlen); new[dirlen] = '/'; memcpy(&new[dirlen + 1], array[i], eltlen);#endif free((__ptr_t) array[i]); array[i] = new; } return 0;}/* Return nonzero if PATTERN contains any metacharacters. Metacharacters can be quoted with backslashes if QUOTE is nonzero. */int __glob_pattern_p(pattern, quote) const char *pattern; int quote;{ register const char *p; int open = 0; for (p = pattern; *p != '\0'; ++p) switch (*p) { case '?': case '*': return 1; case '\\': if (quote && p[1] != '\0') ++p; break; case '[': open = 1; break; case ']': if (open) return 1; break; } return 0;}#ifdef _LIBCweak_alias(__glob_pattern_p, glob_pattern_p)#endif/* Like `glob', but PATTERN is a final pathname component, and matches are searched for in DIRECTORY. The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. The GLOB_APPEND flag is assumed to be set (always appends). */ static int glob_in_dir(pattern, directory, flags, errfunc, pglob) const char *pattern; const char *directory; int flags; int (*errfunc) __P((const char *, int)); glob_t *pglob;{ __ptr_t stream; struct globlink { struct globlink *next; char *name; }; struct globlink *names = NULL; size_t nfound; int meta; int save; stream = ((flags & GLOB_ALTDIRFUNC) ? (*pglob->gl_opendir) (directory) : (__ptr_t) opendir(directory)); if (stream == NULL) { if ((errfunc != NULL && (*errfunc) (directory, errno)) || (flags & GLOB_ERR)) return GLOB_ABORTED; nfound = 0; meta = 0; } else if (pattern[0] == '\0') { /* This is a special case for matching directories like in "*a/". */ names = (struct globlink *) __alloca(sizeof(struct globlink)); names->name = (char *) malloc(1); if (names->name == NULL) goto memory_error; names->name[0] = '\0'; names->next = NULL; nfound = 1; meta = 0; } else { nfound = 0; meta = __glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE)); if (meta) flags |= GLOB_MAGCHAR; while (1) { const char *name; size_t len; struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ? (*pglob->gl_readdir) (stream) : readdir((DIR *) stream)); if (d == NULL) break; if (!REAL_DIR_ENTRY(d)) continue;#ifdef HAVE_D_TYPE /* If we shall match only directories use the information provided by the dirent call if possible. */ if ((flags & GLOB_ONLYDIR) && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR) continue;#endif name = d->d_name; if ((!meta && strcmp(pattern, name) == 0) || wu_fnmatch(pattern, name, (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)#ifdef _AMIGA | FNM_CASEFOLD#endif ) == 0) { struct globlink *new = (struct globlink *) __alloca(sizeof(struct globlink)); len = NAMLEN(d); new->name = (char *) malloc(len + 1); if (new->name == NULL) goto memory_error;#ifdef HAVE_MEMPCPY *((char *) mempcpy((__ptr_t) new->name, name, len)) = '\0';#else memcpy((__ptr_t) new->name, name, len); new->name[len] = '\0';#endif new->next = names; names = new; ++nfound; if (!meta) break; } } } if (nfound == 0 && (flags & GLOB_NOMAGIC) && !meta) flags |= GLOB_NOCHECK; if (nfound == 0 && (flags & GLOB_NOCHECK)) { size_t len = strlen(pattern); nfound = 1; names = (struct globlink *) __alloca(sizeof(struct globlink)); names->next = NULL; names->name = (char *) malloc(len + 1); if (names->name == NULL) goto memory_error;#ifdef HAVE_MEMPCPY *((char *) mempcpy(names->name, pattern, len)) = '\0';#else memcpy(names->name, pattern, len); names->name[len] = '\0';#endif } if (nfound != 0) { pglob->gl_pathv = (char **) realloc(pglob->gl_pathv, (pglob->gl_pathc + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + nfound + 1) * sizeof(char *)); if (pglob->gl_pathv == NULL) goto memory_error; if (flags & GLOB_DOOFFS) while (pglob->gl_pathc < pglob->gl_offs) pglob->gl_pathv[pglob->gl_pathc++] = NULL; for (; names != NULL; names = names->next) pglob->gl_pathv[pglob->gl_pathc++] = names->name; pglob->gl_pathv[pglob->gl_pathc] = NULL; pglob->gl_flags = flags; } save = errno; if (flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir) (stream); else closedir((DIR *) stream); __set_errno(save); return nfound == 0 ? GLOB_NOMATCH : 0; memory_error: { int save = errno; if (flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir) (stream); else closedir((DIR *) stream); __set_errno(save); } while (names != NULL) { if (names->name != NULL) free((__ptr_t) names->name); names = names->next; } return GLOB_NOSPACE;}#endif /* Not ELIDE_CODE. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -