📄 bsd_glob.c
字号:
; if (dc >= pathend_last) { *dc = BG_EOS; err = 1; break; } if (!match(pathend, pattern, restpattern, nocase)) { *pathend = BG_EOS; continue; } err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, restpattern, restpattern_last, pglob, limitp); if (err) break; } if (pglob->gl_flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir)(dirp); else PerlDir_close(dirp); return(err);#ifdef MACOS_TRADITIONAL }#endif}/* * Extend the gl_pathv member of a glob_t structure to accomodate a new item, * add the new item, and update gl_pathc. * * This assumes the BSD realloc, which only copies the block when its size * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic * behavior. * * Return 0 if new item added, error code if memory couldn't be allocated. * * Invariant of the glob_t structure: * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and * gl_pathv points to (gl_offs + gl_pathc + 1) items. */static intglobextend(const Char *path, glob_t *pglob, size_t *limitp){ register char **pathv; register int i; STRLEN newsize, len; char *copy; const Char *p;#ifdef GLOB_DEBUG printf("Adding "); for (p = path; *p; p++) (void)printf("%c", CHAR(*p)); printf("\n");#endif /* GLOB_DEBUG */ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); if (pglob->gl_pathv) pathv = Renew(pglob->gl_pathv,newsize,char*); else Newx(pathv,newsize,char*); if (pathv == NULL) { if (pglob->gl_pathv) { Safefree(pglob->gl_pathv); pglob->gl_pathv = NULL; } return(GLOB_NOSPACE); } if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { /* first time around -- clear initial gl_offs items */ pathv += pglob->gl_offs; for (i = pglob->gl_offs; --i >= 0; ) *--pathv = NULL; } pglob->gl_pathv = pathv; for (p = path; *p++;) ; len = (STRLEN)(p - path); *limitp += len; Newx(copy, p-path, char); if (copy != NULL) { if (g_Ctoc(path, copy, len)) { Safefree(copy); return(GLOB_NOSPACE); } pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; } pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; if ((pglob->gl_flags & GLOB_LIMIT) && newsize + *limitp >= ARG_MAX) { errno = 0; return(GLOB_NOSPACE); } return(copy == NULL ? GLOB_NOSPACE : 0);}/* * pattern matching function for filenames. Each occurrence of the * * pattern causes a recursion level. */static intmatch(register Char *name, register Char *pat, register Char *patend, int nocase){ int ok, negate_range; Char c, k; while (pat < patend) { c = *pat++; switch (c & M_MASK) { case M_ALL: if (pat == patend) return(1); do if (match(name, pat, patend, nocase)) return(1); while (*name++ != BG_EOS) ; return(0); case M_ONE: if (*name++ == BG_EOS) return(0); break; case M_SET: ok = 0; if ((k = *name++) == BG_EOS) return(0); if ((negate_range = ((*pat & M_MASK) == M_NOT)) != BG_EOS) ++pat; while (((c = *pat++) & M_MASK) != M_END) if ((*pat & M_MASK) == M_RNG) { if (nocase) { if (tolower(c) <= tolower(k) && tolower(k) <= tolower(pat[1])) ok = 1; } else { if (c <= k && k <= pat[1]) ok = 1; } pat += 2; } else if (nocase ? (tolower(c) == tolower(k)) : (c == k)) ok = 1; if (ok == negate_range) return(0); break; default: k = *name++; if (nocase ? (tolower(k) != tolower(c)) : (k != c)) return(0); break; } } return(*name == BG_EOS);}/* Free allocated data belonging to a glob_t structure. */voidbsd_globfree(glob_t *pglob){ register int i; register char **pp; if (pglob->gl_pathv != NULL) { pp = pglob->gl_pathv + pglob->gl_offs; for (i = pglob->gl_pathc; i--; ++pp) if (*pp) Safefree(*pp); Safefree(pglob->gl_pathv); pglob->gl_pathv = NULL; }}static DIR *g_opendir(register Char *str, glob_t *pglob){ char buf[MAXPATHLEN]; if (!*str) {#ifdef MACOS_TRADITIONAL my_strlcpy(buf, ":", sizeof(buf));#else my_strlcpy(buf, ".", sizeof(buf));#endif } else { if (g_Ctoc(str, buf, sizeof(buf))) return(NULL); } if (pglob->gl_flags & GLOB_ALTDIRFUNC) return((DIR*)(*pglob->gl_opendir)(buf)); return(PerlDir_open(buf));}static intg_lstat(register Char *fn, Stat_t *sb, glob_t *pglob){ char buf[MAXPATHLEN]; if (g_Ctoc(fn, buf, sizeof(buf))) return(-1); if (pglob->gl_flags & GLOB_ALTDIRFUNC) return((*pglob->gl_lstat)(buf, sb));#ifdef HAS_LSTAT return(PerlLIO_lstat(buf, sb));#else return(PerlLIO_stat(buf, sb));#endif /* HAS_LSTAT */}static intg_stat(register Char *fn, Stat_t *sb, glob_t *pglob){ char buf[MAXPATHLEN]; if (g_Ctoc(fn, buf, sizeof(buf))) return(-1); if (pglob->gl_flags & GLOB_ALTDIRFUNC) return((*pglob->gl_stat)(buf, sb)); return(PerlLIO_stat(buf, sb));}static Char *g_strchr(Char *str, int ch){ do { if (*str == ch) return (str); } while (*str++); return (NULL);}static intg_Ctoc(register const Char *str, char *buf, STRLEN len){ while (len--) { if ((*buf++ = (char)*str++) == BG_EOS) return (0); } return (1);}#ifdef GLOB_DEBUGstatic voidqprintf(const char *str, register Char *s){ register Char *p; (void)printf("%s:\n", str); for (p = s; *p; p++) (void)printf("%c", CHAR(*p)); (void)printf("\n"); for (p = s; *p; p++) (void)printf("%c", *p & M_PROTECT ? '"' : ' '); (void)printf("\n"); for (p = s; *p; p++) (void)printf("%c", ismeta(*p) ? '_' : ' '); (void)printf("\n");}#endif /* GLOB_DEBUG */#ifdef MACOS_TRADITIONAL/* Replace the last occurrence of the pattern ":[^:]+::", e.g. ":lib::", with a single ':', if possible. It is not an error, if the pattern doesn't match (we return -1), but if there are two consecutive colons '::', there must be a preceding ':[^:]+'. Hence, a volume path like "HD::" is considered to be an error (we return 1), that is, it can't be resolved. We return 0 on success.*/static shortupdir(char *path){ char *pb, *pe, *lastchar; char *bgn_mark, *end_mark; char *f, *m, *b; /* front, middle, back */ size_t len; len = strlen(path); lastchar = path + (len-1); b = lastchar; m = lastchar-1; f = lastchar-2; /* find a '[^:]::' (e.g. b::) pattern ... */ while ( !( (*f != BG_SEP) && (*m == BG_SEP) && (*b == BG_SEP) ) && (f >= path)) { f--; m--; b--; } if (f < path) { /* no (more) match */ return -1; } end_mark = b; /* ... and now find its preceding colon ':' */ while ((*f != BG_SEP) && (f >= path)) { f--; } if (f < path) { /* No preceding colon found, must be a volume path. We can't move up the tree and that's an error */ return 1; } bgn_mark = f; /* Shrink path, i.e. exclude all characters between bgn_mark and end_mark */ pb = bgn_mark; pe = end_mark; while (*pb++ = *pe++) ; return 0;}/* Resolve all updirs in pattern. */static shortresolve_updirs(char *new_pattern){ short err; do { err = updir(new_pattern); } while (!err); if (err == 1) { return NO_UPDIR_ERR; } return 0;}/* Remove a trailing colon from the path, but only if it's not a volume path (e.g. HD:) and not a path consisting solely of colons. */static voidremove_trColon(char *path){ char *lastchar, *lc; /* if path matches the pattern /:[^:]+:$/, we can remove the trailing ':' */ lc = lastchar = path + (strlen(path) - 1); if (*lastchar == BG_SEP) { /* there's a trailing ':', there must be at least one preceding char != ':' and a preceding ':' */ lc--; if ((*lc != BG_SEP) && (lc >= path)) { lc--; } else { return; } while ((*lc != BG_SEP) && (lc >= path)) { lc--; } if (lc >= path) { /* ... there's a preceding ':', we remove the trailing colon */ *lastchar = BG_EOS; } }}/* With the GLOB_MARK flag on, we append a colon, if pathbuf is a directory. If the directory name contains no colons, e.g. 'lib', we can't simply append a ':', since this (e.g. 'lib:') is not a valid (relative) path on Mac OS. Instead, we add a leading _and_ trailing ':'. */static shortglob_mark_Mac(Char *pathbuf, Char *pathend, Char *pathend_last){ Char *p, *pe; Boolean is_file = true; /* check if pathbuf contains a ':', i.e. is not a file name */ p = pathbuf; while (*p != BG_EOS) { if (*p == BG_SEP) { is_file = false; break; } p++; } if (is_file) { if (pathend+2 > pathend_last) { return (1); } /* right shift one char */ pe = p = pathend; p--; pathend++; while (p >= pathbuf) { *pe-- = *p--; } /* first char becomes a colon */ *pathbuf = BG_SEP; /* append a colon */ *pathend++ = BG_SEP; *pathend = BG_EOS; } else { if (pathend+1 > pathend_last) { return (1); } *pathend++ = BG_SEP; *pathend = BG_EOS; } return 0;}/* Return a FSSpec record for the specified volume (borrowed from MacPerl.xs). */static OSErrGetVolInfo(short volume, Boolean indexed, FSSpec* spec){ OSErr err; /* OSErr: 16-bit integer */ HParamBlockRec pb; pb.volumeParam.ioNamePtr = spec->name; pb.volumeParam.ioVRefNum = indexed ? 0 : volume; pb.volumeParam.ioVolIndex = indexed ? volume : 0; if (err = PBHGetVInfoSync(&pb)) return err; spec->vRefNum = pb.volumeParam.ioVRefNum; spec->parID = 1; return noErr; /* 0 */}/* Extract a C name from a FSSpec. Note that there are no leading or trailing colons. */static voidname_f_FSSpec(StrFileName name, FSSpec *spec){ unsigned char *nc; const short len = spec->name[0]; short i; /* FSSpec.name is a Pascal string, convert it to C ... */ nc = name; for (i=1; i<=len; i++) { *nc++ = spec->name[i]; } *nc = BG_EOS;}#endif /* MACOS_TRADITIONAL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -