📄 eval.c
字号:
* word is generated if $# is 0 (unless there is * other stuff inside the quotes). */ type = XBASE; if (f&DOBLANK) { doblank--; /* not really correct: x=; "$x$@" should * generate a null argument and * set A; "${@:+}" shouldn't. */ if (dp == Xstring(ds, dp)) word = IFS_WS; } continue; case XSUB: if ((c = *x.str++) == 0) { type = XBASE; if (f&DOBLANK) doblank--; continue; } break; case XARGSEP: type = XARG; quote = 1; case XARG: if ((c = *x.str++) == '\0') { /* force null words to be created so * set -- '' 2 ''; foo "$@" will do * the right thing */ if (quote && x.split) word = IFS_WORD; if ((x.str = *x.u.strv++) == NULL) { type = XBASE; if (f&DOBLANK) doblank--; continue; } c = ifs0; if (c == 0) { if (quote && !x.split) continue; c = ' '; } if (quote && x.split) { /* terminate word for "$@" */ type = XARGSEP; quote = 0; } } break; case XCOM: if (newlines) { /* Spit out saved nl's */ c = '\n'; --newlines; } else { while ((c = shf_getc(x.u.shf)) == 0 || c == '\n') if (c == '\n') newlines++; /* Save newlines */ if (newlines && c != EOF) { shf_ungetc(c, x.u.shf); c = '\n'; --newlines; } } if (c == EOF) { newlines = 0; shf_close(x.u.shf); if (x.split) subst_exstat = waitlast(); type = XBASE; if (f&DOBLANK) doblank--; continue; } break; } /* check for end of word or IFS separation */ if (c == 0 || (!quote && (f & DOBLANK) && doblank && !make_magic && ctype(c, C_IFS))) { /* How words are broken up: * | value of c * word | ws nws 0 * ----------------------------------- * IFS_WORD w/WS w/NWS w * IFS_WS -/WS w/NWS - * IFS_NWS -/NWS w/NWS w * (w means generate a word) * Note that IFS_NWS/0 generates a word (at&t ksh * doesn't do this, but POSIX does). */ if (word == IFS_WORD || (!ctype(c, C_IFSWS) && (c || word == IFS_NWS))) { char *p; *dp++ = '\0'; p = Xclose(ds, dp);#ifdef BRACE_EXPAND if (fdo & DOBRACE_) /* also does globbing */ alt_expand(wp, p, p, p + Xlength(ds, (dp - 1)), fdo | (f & DOMARKDIRS)); else#endif /* BRACE_EXPAND */ if (fdo & DOGLOB) glob(p, wp, f & DOMARKDIRS); else if ((f & DOPAT) || !(fdo & DOMAGIC_)) XPput(*wp, p); else XPput(*wp, debunk(p, p)); fdo = 0; saw_eq = 0; tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0; if (c != 0) Xinit(ds, dp, 128, ATEMP); } if (c == 0) return; if (word != IFS_NWS) word = ctype(c, C_IFSWS) ? IFS_WS : IFS_NWS; } else { /* age tilde_ok info - ~ code tests second bit */ tilde_ok <<= 1; /* mark any special second pass chars */ if (!quote) switch (c) { case '[': case NOT: case '-': case ']': /* For character classes - doesn't hurt * to have magic !,-,]'s outside of * [...] expressions. */ if (f & (DOPAT | DOGLOB)) { fdo |= DOMAGIC_; if (c == '[') fdo |= f & DOGLOB; *dp++ = MAGIC; } break; case '*': case '?': if (f & (DOPAT | DOGLOB)) { fdo |= DOMAGIC_ | (f & DOGLOB); *dp++ = MAGIC; } break;#ifdef BRACE_EXPAND case OBRACE: case ',': case CBRACE: if ((f & DOBRACE_) && (c == OBRACE || (fdo & DOBRACE_))) { fdo |= DOBRACE_|DOMAGIC_; *dp++ = MAGIC; } break;#endif /* BRACE_EXPAND */ case '=': /* Note first unquoted = for ~ */ if (!(f & DOTEMP_) && !saw_eq) { saw_eq = 1; tilde_ok = 1; } break; case PATHSEP: /* : */ /* Note unquoted : for ~ */ if (!(f & DOTEMP_) && (f & DOASNTILDE)) tilde_ok = 1; break; case '~': /* tilde_ok is reset whenever * any of ' " $( $(( ${ } are seen. * Note that tilde_ok must be preserved * through the sequence ${A=a=}~ */ if (type == XBASE && (f & (DOTILDE|DOASNTILDE)) && (tilde_ok & 2)) { char *p, *dp_x; dp_x = dp; p = maybe_expand_tilde(sp, &ds, &dp_x, f & DOASNTILDE); if (p) { if (dp != dp_x) word = IFS_WORD; dp = dp_x; sp = p; continue; } } break; } else quote &= ~2; /* undo temporary */ if (make_magic) { make_magic = 0; fdo |= DOMAGIC_ | (f & DOGLOB); *dp++ = MAGIC; } else if (ISMAGIC(c)) { fdo |= DOMAGIC_; *dp++ = MAGIC; } *dp++ = c; /* save output char */ word = IFS_WORD; } }}/* * Prepare to generate the string returned by ${} substitution. */static intvarsub(xp, sp, word, stypep, slenp) Expand *xp; char *sp; char *word; int *stypep; /* becomes qualifier type */ int *slenp; /* " " len (=, :=, etc.) valid iff *stypep != 0 */{ int c; int state; /* next state: XBASE, XARG, XSUB, XNULLSUB */ int stype; /* substitution type */ int slen; char *p; struct tbl *vp; if (sp[0] == '\0') /* Bad variable name */ return -1; xp->var = (struct tbl *) 0; /* ${#var}, string length or array size */ if (sp[0] == '#' && (c = sp[1]) != '\0') { int zero_ok = 0; /* Can't have any modifiers for ${#...} */ if (*word != CSUBST) return -1; sp++; /* Check for size of array */ if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { int n = 0; int max = 0; vp = global(arrayname(sp)); if (vp->flag & (ISSET|ARRAY)) zero_ok = 1; for (; vp; vp = vp->u.array) if (vp->flag & ISSET) { max = vp->index + 1; n++; } c = n; /* ksh88/ksh93 go for number, not max index */ } else if (c == '*' || c == '@') c = e->loc->argc; else { p = str_val(global(sp)); zero_ok = p != null; c = strlen(p); } if (Flag(FNOUNSET) && c == 0 && !zero_ok) errorf("%s: parameter not set", sp); *stypep = 0; /* unqualified variable/string substitution */ xp->str = str_save(ulton((unsigned long)c, 10), ATEMP); return XSUB; } /* Check for qualifiers in word part */ stype = 0; c = word[slen = 0] == CHAR ? word[1] : 0; if (c == ':') { slen += 2; stype = 0x80; c = word[slen + 0] == CHAR ? word[slen + 1] : 0; } if (ctype(c, C_SUBOP1)) { slen += 2; stype |= c; } else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */ slen += 2; stype = c; if (word[slen + 0] == CHAR && c == word[slen + 1]) { stype |= 0x80; slen += 2; } } else if (stype) /* : is not ok */ return -1; if (!stype && *word != CSUBST) return -1; *stypep = stype; *slenp = slen; c = sp[0]; if (c == '*' || c == '@') { switch (stype & 0x7f) { case '=': /* can't assign to a vector */ case '%': /* can't trim a vector (yet) */ case '#': return -1; } if (e->loc->argc == 0) { xp->str = null; state = c == '@' ? XNULLSUB : XSUB; } else { xp->u.strv = (const char **) e->loc->argv + 1; xp->str = *xp->u.strv++; xp->split = c == '@'; /* $@ */ state = XARG; } } else { if ((p=strchr(sp,'[')) && (p[1]=='*'||p[1]=='@') && p[2]==']') { XPtrV wv; switch (stype & 0x7f) { case '=': /* can't assign to a vector */ case '%': /* can't trim a vector (yet) */ case '#': return -1; } XPinit(wv, 32); vp = global(arrayname(sp)); for (; vp; vp = vp->u.array) { if (!(vp->flag&ISSET)) continue; XPput(wv, str_val(vp)); } if (XPsize(wv) == 0) { xp->str = null; state = p[1] == '@' ? XNULLSUB : XSUB; XPfree(wv); } else { XPput(wv, 0); xp->u.strv = (const char **) XPptrv(wv); xp->str = *xp->u.strv++; xp->split = p[1] == '@'; /* ${foo[@]} */ state = XARG; } } else { /* Can't assign things like $! or $1 */ if ((stype & 0x7f) == '=' && (ctype(*sp, C_VAR1) || digit(*sp))) return -1; xp->var = global(sp); xp->str = str_val(xp->var); state = XSUB; } } c = stype&0x7f; /* test the compiler's code generator */ if (ctype(c, C_SUBOP2) || (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */ c == '=' || c == '-' || c == '?' : c == '+')) state = XBASE; /* expand word instead of variable value */ if (Flag(FNOUNSET) && xp->str == null && (ctype(c, C_SUBOP2) || (state != XBASE && c != '+'))) errorf("%s: parameter not set", sp); return state;}/* * Run the command in $(...) and read its output. */static intcomsub(xp, cp) register Expand *xp; char *cp;{ Source *s, *sold; register struct op *t; struct shf *shf; s = pushs(SSTRING, ATEMP); s->start = s->str = cp; sold = source; t = compile(s); source = sold; if (t == NULL) return XBASE; if (t != NULL && t->type == TCOM && /* $(<file) */ *t->args == NULL && *t->vars == NULL && t->ioact != NULL) { register struct ioword *io = *t->ioact; char *name; if ((io->flag&IOTYPE) != IOREAD) errorf("funny $() command: %s", snptreef((char *) 0, 32, "%R", io)); shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); if (shf == NULL) errorf("%s: cannot open $() input", name); xp->split = 0; /* no waitlast() */ } else { int ofd1, pv[2]; openpipe(pv); shf = shf_fdopen(pv[0], SHF_RD, (struct shf *) 0); ofd1 = savefd(1, 0); /* fd 1 may be closed... */ ksh_dup2(pv[1], 1, FALSE); close(pv[1]); execute(t, XFORK|XXCOM|XPIPEO); restfd(1, ofd1); startlast(); xp->split = 1; /* waitlast() */ } xp->u.shf = shf; return XCOM;}/* * perform #pattern and %pattern substitution in ${} */static char *trimsub(str, pat, how) register char *str; char *pat; int how;{ register char *end = strchr(str, 0); register char *p, c; switch (how&0xff) { /* UCHAR_MAX maybe? */ case '#': /* shortest at begining */ for (p = str; p <= end; p++) { c = *p; *p = '\0'; if (gmatch(str, pat, FALSE)) { *p = c; return p; } *p = c; } break; case '#'|0x80: /* longest match at begining */ for (p = end; p >= str; p--) { c = *p; *p = '\0'; if (gmatch(str, pat, FALSE)) { *p = c; return p; } *p = c; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -