📄 eval.c
字号:
case '%': /* shortest match at end */ for (p = end; p >= str; p--) { if (gmatch(p, pat, FALSE)) return str_nsave(str, p - str, ATEMP); } break; case '%'|0x80: /* longest match at end */ for (p = str; p <= end; p++) { if (gmatch(p, pat, FALSE)) return str_nsave(str, p - str, ATEMP); } break; } return str; /* no match, return string */}/* * glob * Name derived from V6's /etc/glob, the program that expanded filenames. *//* XXX cp not const 'cause slashes are temporarily replaced with nulls... */static voidglob(cp, wp, markdirs) char *cp; register XPtrV *wp; int markdirs;{ int oldsize = XPsize(*wp); if (glob_str(cp, wp, markdirs) == 0) XPput(*wp, debunk(cp, cp)); else qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), xstrcmp);}#define GF_NONE 0#define GF_EXCHECK BIT(0) /* do existance check on file */#define GF_GLOBBED BIT(1) /* some globbing has been done */#define GF_MARKDIR BIT(2) /* add trailing / to directories *//* Apply file globbing to cp and store the matching files in wp. Returns * the number of matches found. */intglob_str(cp, wp, markdirs) char *cp; XPtrV *wp; int markdirs;{ int oldsize = XPsize(*wp); XString xs; char *xp; Xinit(xs, xp, 256, ATEMP); globit(&xs, &xp, cp, wp, markdirs ? GF_MARKDIR : GF_NONE); Xfree(xs, xp); return XPsize(*wp) - oldsize;}static voidglobit(xs, xpp, sp, wp, check) XString *xs; /* dest string */ char **xpp; /* ptr to dest end */ char *sp; /* source path */ register XPtrV *wp; /* output list */ int check; /* GF_* flags */{ register char *np; /* next source component */ char *xp = *xpp; char *se; char odirsep; /* This to allow long expansions to be interrupted */ intrcheck(); if (sp == NULL) { /* end of source path */ /* We only need to check if the file exists if a pattern * is followed by a non-pattern (eg, foo*x/bar; no check * is needed for foo* since the match must exist) or if * any patterns were expanded and the markdirs option is set. * Symlinks make things a bit tricky... */ if ((check & GF_EXCHECK) || ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {#define stat_check() (stat_done ? stat_done : \ (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \ ? -1 : 1)) struct stat lstatb, statb; int stat_done = 0; /* -1: failed, 1 ok */ if (lstat(Xstring(*xs, xp), &lstatb) < 0) return; /* special case for systems which strip trailing * slashes from regular files (eg, /etc/passwd/). * SunOS 4.1.3 does this... */ if ((check & GF_EXCHECK) && xp > Xstring(*xs, xp) && ISDIRSEP(xp[-1]) && !S_ISDIR(lstatb.st_mode)#ifdef S_ISLNK && (!S_ISLNK(lstatb.st_mode) || stat_check() < 0 || !S_ISDIR(statb.st_mode))#endif /* S_ISLNK */ ) return; /* Possibly tack on a trailing / if there isn't already * one and if the file is a directory or a symlink to a * directory */ if (((check & GF_MARKDIR) && (check & GF_GLOBBED)) && xp > Xstring(*xs, xp) && !ISDIRSEP(xp[-1]) && (S_ISDIR(lstatb.st_mode)#ifdef S_ISLNK || (S_ISLNK(lstatb.st_mode) && stat_check() > 0 && S_ISDIR(statb.st_mode))#endif /* S_ISLNK */ )) { *xp++ = DIRSEP; *xp = '\0'; } }#ifdef OS2 /* Done this way to avoid bug in gcc 2.7.2... */ /* Ugly kludge required for command * completion - see how search_access() * is implemented for OS/2... */# define KLUDGE_VAL 4#else /* OS2 */# define KLUDGE_VAL 0#endif /* OS2 */ XPput(*wp, str_nsave(Xstring(*xs, xp), Xlength(*xs, xp) + KLUDGE_VAL, ATEMP)); return; } if (xp > Xstring(*xs, xp)) *xp++ = DIRSEP; while (ISDIRSEP(*sp)) { Xcheck(*xs, xp); *xp++ = *sp++; } np = ksh_strchr_dirsep(sp); if (np != NULL) { se = np; odirsep = *np; /* don't assume DIRSEP, can be multiple kinds */ *np++ = '\0'; } else { odirsep = '\0'; /* keep gcc quiet */ se = sp + strlen(sp); } /* Check if sp needs globbing - done to avoid pattern checks for strings * containing MAGIC characters, open ['s without the matching close ], * etc. (otherwise opendir() will be called which may fail because the * directory isn't readable - if no globbing is needed, only execute * permission should be required (as per POSIX)). */ if (!has_globbing(sp, se)) { XcheckN(*xs, xp, se - sp + 1); debunk(xp, sp); xp += strlen(xp); *xpp = xp; globit(xs, xpp, np, wp, check); } else { DIR *dirp; struct dirent *d; char *name; int len; int prefix_len; /* xp = *xpp; copy_non_glob() may have re-alloc'd xs */ *xp = '\0'; prefix_len = Xlength(*xs, xp); dirp = ksh_opendir(prefix_len ? Xstring(*xs, xp) : "."); if (dirp == NULL) goto Nodir; while ((d = readdir(dirp)) != NULL) { name = d->d_name; if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) continue; /* always ignore . and .. */ if ((*name == '.' && *sp != '.') || !gmatch(name, sp, TRUE)) continue; len = NLENGTH(d) + 1; XcheckN(*xs, xp, len); memcpy(xp, name, len); *xpp = xp + len - 1; globit(xs, xpp, np, wp, (check & GF_MARKDIR) | GF_GLOBBED | (np ? GF_EXCHECK : GF_NONE)); xp = Xstring(*xs, xp) + prefix_len; } closedir(dirp); Nodir:; } if (np != NULL) *--np = odirsep;}#if 0/* Check if p contains something that needs globbing; if it does, 0 is * returned; if not, p is copied into xs/xp after stripping any MAGICs */static int copy_non_glob ARGS((XString *xs, char **xpp, char *p));static intcopy_non_glob(xs, xpp, p) XString *xs; char **xpp; char *p;{ char *xp; int len = strlen(p); XcheckN(*xs, *xpp, len); xp = *xpp; for (; *p; p++) { if (ISMAGIC(*p)) { int c = *++p; if (c == '*' || c == '?') return 0; if (*p == '[') { char *q = p + 1; if (ISMAGIC(*q) && q[1] == NOT) q += 2; if (ISMAGIC(*q) && q[1] == ']') q += 2; for (; *q; q++) if (ISMAGIC(*q) && *++q == ']') return 0; /* pass a literal [ through */ } /* must be a MAGIC-MAGIC, or MAGIC-!, MAGIC--, etc. */ } *xp++ = *p; } *xp = '\0'; *xpp = xp; return 1;}#endif /* 0 *//* remove MAGIC from string */char *debunk(dp, sp) char *dp; const char *sp;{ char *d, *s; if ((s = strchr(sp, MAGIC))) { memcpy(dp, sp, s - sp); for (d = dp + (s - sp); *s; s++) if (!ISMAGIC(*s) || !(*++s & 0x80) || !strchr("*+?@! ", *s & 0x7f)) *d++ = *s; else { /* extended pattern operators: *+?@! */ if ((*s & 0x7f) != ' ') *d++ = *s & 0x7f; *d++ = '('; } *d = '\0'; } else if (dp != sp) strcpy(dp, sp); return dp;}/* Check if p is an unquoted name, possibly followed by a / or :. If so * puts the expanded version in *dcp,dp and returns a pointer in p just * past the name, otherwise returns 0. */static char *maybe_expand_tilde(p, dsp, dpp, isassign) char *p; XString *dsp; char **dpp; int isassign;{ XString ts; char *dp = *dpp; char *tp, *r; Xinit(ts, tp, 16, ATEMP); /* : only for DOASNTILDE form */ while (p[0] == CHAR && !ISDIRSEP(p[1]) && (!isassign || p[1] != PATHSEP)) { Xcheck(ts, tp); *tp++ = p[1]; p += 2; } *tp = '\0'; r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? tilde(Xstring(ts, tp)) : (char *) 0; Xfree(ts, tp); if (r) { while (*r) { Xcheck(*dsp, dp); if (ISMAGIC(*r)) *dp++ = MAGIC; *dp++ = *r++; } *dpp = dp; r = p; } return r;}/* * tilde expansion * * based on a version by Arnold Robbins */static char *tilde(cp) char *cp;{ char *dp; if (cp[0] == '\0') dp = str_val(global("HOME")); else if (cp[0] == '+' && cp[1] == '\0') dp = str_val(global("PWD")); else if (cp[0] == '-' && cp[1] == '\0') dp = str_val(global("OLDPWD")); else dp = homedir(cp); /* If HOME, PWD or OLDPWD are not set, don't expand ~ */ if (dp == null) dp = (char *) 0; return dp;}/* * map userid to user's home directory. * note that 4.3's getpw adds more than 6K to the shell, * and the YP version probably adds much more. * we might consider our own version of getpwnam() to keep the size down. */static char *homedir(name) char *name;{ register struct tbl *ap; ap = tenter(&homedirs, name, hash(name)); if (!(ap->flag & ISSET)) {#ifdef OS2 /* No usernames in OS2 - punt */ return NULL;#else /* OS2 */ struct passwd *pw; pw = getpwnam(name); if (pw == NULL) return NULL; ap->val.s = str_save(pw->pw_dir, APERM); ap->flag |= DEFINED|ISSET|ALLOC;#endif /* OS2 */ } return ap->val.s;}#ifdef BRACE_EXPANDstatic voidalt_expand(wp, start, exp_start, end, fdo) XPtrV *wp; char *start, *exp_start; char *end; int fdo;{ int UNINITIALIZED(count); char *brace_start, *brace_end, *UNINITIALIZED(comma); char *field_start; char *p; /* search for open brace */ for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != OBRACE; p += 2) ; brace_start = p; /* find matching close brace, if any */ if (p) { comma = (char *) 0; count = 1; for (p += 2; *p && count; p++) { if (ISMAGIC(*p)) { if (*++p == OBRACE) count++; else if (*p == CBRACE) --count; else if (*p == ',' && count == 1) comma = p; } } } /* no valid expansions... */ if (!p || count != 0) { /* Note that given a{{b,c} we do not expand anything (this is * what at&t ksh does. This may be changed to do the {b,c} * expansion. } */ if (fdo & DOGLOB) glob(start, wp, fdo & DOMARKDIRS); else XPput(*wp, debunk(start, start)); return; } brace_end = p; if (!comma) { alt_expand(wp, start, brace_end, end, fdo); return; } /* expand expression */ field_start = brace_start + 2; count = 1; for (p = brace_start + 2; p != brace_end; p++) { if (ISMAGIC(*p)) { if (*++p == OBRACE) count++; else if ((*p == CBRACE && --count == 0) || (*p == ',' && count == 1)) { char *new; int l1, l2, l3; l1 = brace_start - start; l2 = (p - 1) - field_start; l3 = end - brace_end; new = (char *) alloc(l1 + l2 + l3 + 1, ATEMP); memcpy(new, start, l1); memcpy(new + l1, field_start, l2); memcpy(new + l1 + l2, brace_end, l3); new[l1 + l2 + l3] = '\0'; alt_expand(wp, new, new + l1, new + l1 + l2 + l3, fdo); field_start = p + 1; } } } return;}#endif /* BRACE_EXPAND */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -