diff options
-rw-r--r-- | Src/cond.c | 31 | ||||
-rw-r--r-- | Src/loop.c | 36 | ||||
-rw-r--r-- | Src/parse.c | 26 | ||||
-rw-r--r-- | Src/pattern.c | 33 | ||||
-rw-r--r-- | Src/utils.c | 48 | ||||
-rw-r--r-- | Src/zsh.h | 20 |
6 files changed, 155 insertions, 39 deletions
diff --git a/Src/cond.c b/Src/cond.c index c0a3235be..caa675f2e 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -107,16 +107,15 @@ evalcond(Cond c) left = dupstring((char *) c->left); singsub(&left); untokenize(left); - if (c->right) { + if (c->right && c->type != COND_STREQ && c->type != COND_STRNEQ) { right = dupstring((char *) c->right); singsub(&right); - if (c->type != COND_STREQ && c->type != COND_STRNEQ) - untokenize(right); + untokenize(right); } if (tracingcond) { if (c->type < COND_MOD) { - char *rt = (char *)right; + char *rt = (char *) right; if (c->type == COND_STREQ || c->type == COND_STRNEQ) { rt = dupstring(rt); untokenize(rt); @@ -168,9 +167,29 @@ evalcond(Cond c) switch (c->type) { case COND_STREQ: - return matchpat(left, right); case COND_STRNEQ: - return !matchpat(left, right); + { + Patprog pprog = c->prog; + int test; + + if (pprog == dummy_patprog1 || pprog == dummy_patprog2) { + char *opat; + int save; + + right = opat = dupstring((char *) c->right); + singsub(&right); + save = (!strcmp(opat, right) && pprog != dummy_patprog2); + + if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) + zerr("bad pattern: %s", right, 0); + else if (save) + c->prog = pprog; + } + test = (pprog && pattry(pprog, left)); + + return (c->type == COND_STREQ ? test : !test); + } case COND_STRLT: return strcmp(left, right) < 0; case COND_STRGTR: diff --git a/Src/loop.c b/Src/loop.c index 5937efc7c..b74de41ed 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -422,10 +422,13 @@ execcase(Cmd cmd, LinkList args, int flags) char *word; List *l; char **p; + Patprog *pp, pprog; + int save; node = cmd->u.casecmd; l = node->lists; p = node->pats; + pp = node->progs; word = dupstring(*p++); singsub(&word); @@ -435,22 +438,47 @@ execcase(Cmd cmd, LinkList args, int flags) if (node) { cmdpush(CS_CASE); while (*p) { - char *pat = dupstring(*p + 1); - singsub(&pat); + char *pat = NULL, *opat; + + pprog = NULL; + save = 0; + if (isset(XTRACE)) { - char *pat2 = dupstring(pat); + char *pat2; + + opat = pat = dupstring(*p + 1); + singsub(&pat); + save = (!strcmp(pat, opat) && *pp != dummy_patprog2); + + pat2 = dupstring(pat); untokenize(pat2); printprompt4(); fprintf(stderr, "case %s (%s)\n", word, pat2); fflush(stderr); } - if (matchpat(word, pat)) { + if (*pp != dummy_patprog1 && *pp != dummy_patprog2) + pprog = *pp; + + if (!pprog) { + if (!pat) { + opat = pat = dupstring(*p + 1); + singsub(&pat); + save = (!strcmp(pat, opat) && *pp != dummy_patprog2); + } + if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) + zerr("bad pattern: %s", pat, 0); + else if (save) + *pp = pprog; + } + if (pprog && pattry(pprog, word)) { do { execlist(*l++, 1, **p == ';' && (flags & CFLAG_EXEC)); } while(**p++ == '&' && *p); break; } p++; + pp++; l++; } cmdpop(); diff --git a/Src/parse.c b/Src/parse.c index d0a9bc45f..e5d067f8d 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -539,6 +539,7 @@ par_case(Cmd c) LinkList pats, lists; int n = 1; char **pp; + Patprog *ppp; List *ll; LinkNode no; struct casecmd *cc; @@ -659,11 +660,17 @@ par_case(Cmd c) incmdpos = 1; yylex(); - cc->pats = (char **)alloc((n + 1) * sizeof(char *)); + cc->pats = (char **) alloc((n + 1) * sizeof(char *)); + cc->progs = (Patprog *) alloc((n + 1) * sizeof(Patprog)); - for (pp = cc->pats, no = firstnode(pats); no; incnode(no)) + for (pp = cc->pats, ppp = cc->progs, no = firstnode(pats); + no; incnode(no)) { *pp++ = (char *)getdata(no); + *ppp++ = dummy_patprog1; + } *pp = NULL; + *ppp = NULL; + cc->lists = (List *) alloc((n + 1) * sizeof(List)); for (ll = cc->lists, no = firstnode(lists); no; incnode(no), ll++) if (!(*ll = (List) getdata(no))) @@ -1438,18 +1445,21 @@ par_cond_triple(char *a, char *b, char *c) Cond n = (Cond) make_cond(); int t0; - n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); n->left = (void *) a; n->right = (void *) c; + n->prog = dummy_patprog1; if ((b[0] == Equals || b[0] == '=') && - (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) + (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { + n->ntype = NT_SET(N_COND, NT_STR, NT_STR, NT_PAT, 0); n->type = COND_STREQ; - else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) + } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) { + n->ntype = NT_SET(N_COND, NT_STR, NT_STR, NT_PAT, 0); n->type = COND_STRNEQ; - else if (b[0] == '-') { - if ((t0 = get_cond_num(b + 1)) > -1) + } else if (b[0] == '-') { + if ((t0 = get_cond_num(b + 1)) > -1) { + n->ntype = NT_SET(N_COND, NT_STR, NT_STR, 0, 0); n->type = t0 + COND_NT; - else { + } else { char *d[3]; n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0); diff --git a/Src/pattern.c b/Src/pattern.c index 3b226c92f..6b503e36d 100644 --- a/Src/pattern.c +++ b/Src/pattern.c @@ -427,8 +427,13 @@ patcompile(char *exp, int inflags, char **endexp) * The pattern was compiled in a fixed buffer: unless told otherwise, * we stick the compiled pattern on the heap. This is necessary * for files where we will often be compiling multiple segments at once. + * But if we get the ZDUP flag w always put it in zalloc()ed memory. */ - if (!(patflags & PAT_STATIC)) { + if (patflags & PAT_ZDUP) { + Patprog newp = (Patprog)zalloc(patsize); + memcpy((char *)newp, (char *)p, patsize); + p = newp; + } else if (!(patflags & PAT_STATIC)) { Patprog newp = (Patprog)zhalloc(patsize); memcpy((char *)newp, (char *)p, patsize); p = newp; @@ -2188,6 +2193,32 @@ static int patrepeat(Upat p) return count; } +/* Duplicate a patprog. */ + +/**/ +Patprog +duppatprog(Patprog prog) +{ + if (prog && prog != dummy_patprog1 && prog != dummy_patprog2) { + Patprog ret = (Patprog) alloc(prog->size); + + memcpy(ret, prog, prog->size); + + return ret; + } + return prog; +} + +/* Free a patprog. */ + +/**/ +void +freepatprog(Patprog prog) +{ + if (prog && prog != dummy_patprog1 && prog != dummy_patprog2) + zfree(prog, prog->size); +} + /**/ #ifdef ZSH_PAT_DEBUG diff --git a/Src/utils.c b/Src/utils.c index 1162968fd..3f0649f69 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1933,9 +1933,9 @@ static int flagtab[N_COUNT] = { NT_SET(N_PLINE, NT_NODE, NT_NODE, 0, 0), NT_SET(N_CMD, NT_NODE, NT_STR | NT_LIST, NT_NODE | NT_LIST, NT_NODE | NT_LIST), NT_SET(N_REDIR, NT_STR, 0, 0, 0), - NT_SET(N_COND, NT_NODE, NT_NODE, 0, 0), + NT_SET(N_COND, NT_NODE, NT_NODE, NT_PAT, 0), NT_SET(N_FOR, NT_STR, NT_STR, NT_STR, NT_NODE), - NT_SET(N_CASE, NT_STR | NT_ARR, NT_NODE | NT_ARR, 0, 0), + NT_SET(N_CASE, NT_STR | NT_ARR, NT_PAT | NT_ARR, NT_NODE | NT_ARR, 0), NT_SET(N_IF, NT_NODE | NT_ARR, NT_NODE | NT_ARR, 0, 0), NT_SET(N_WHILE, NT_NODE, NT_NODE, 0, 0), NT_SET(N_VARASG, NT_STR, NT_STR, NT_STR | NT_LIST, 0), @@ -1983,18 +1983,27 @@ dupstruct(void *a) case NT_STR: n = dupstring(on); break; + case NT_PAT: + n = duppatprog(on); + break; case NT_LIST | NT_NODE: n = duplist(on, (VFunc) dupstruct); break; case NT_LIST | NT_STR: n = duplist(on, (VFunc) (useheap ? dupstring : ztrdup)); break; + case NT_LIST | NT_PAT: + n = duplist(on, (VFunc) duppatprog); + break; case NT_NODE | NT_ARR: n = duparray(on, (VFunc) dupstruct); break; case NT_STR | NT_ARR: n = duparray(on, (VFunc) (useheap ? dupstring : ztrdup)); break; + case NT_PAT | NT_ARR: + n = duparray(on, (VFunc) duppatprog); + break; default: DPUTS(1, "BUG: bad node type in dupstruct()"); abort(); @@ -2055,32 +2064,49 @@ ifreestruct(void *a) case NT_STR: zsfree((char *) n); break; + case NT_PAT: + freepatprog((Patprog) n); + break; case NT_LIST | NT_NODE: freelinklist((LinkList) n, (FreeFunc) freestruct); break; - case NT_NODE | NT_ARR: - { - void **p = (void **) n; - - while (*p) - freestruct(*p++); - zfree(n, sizeof(void *) * (p + 1 - (void **) n)); - break; - } case NT_LIST | NT_STR: freelinklist((LinkList) n, (FreeFunc) zsfree); break; + case NT_LIST | NT_PAT: + freelinklist((LinkList) n, (FreeFunc) freepatprog); + break; + case NT_NODE | NT_ARR: + { + void **p = (void **) n; + + while (*p) + freestruct(*p++); + zfree(n, sizeof(void *) * (p + 1 - (void **) n)); + break; + } case NT_STR | NT_ARR: freearray((char **) n); break; + case NT_PAT | NT_ARR: + { + Patprog *p = (Patprog *) n; + + while (*p) + freepatprog(*p++); + zfree(n, sizeof(void *) * ((void **) p + 1 - (void **) n)); + break; + } default: DPUTS(1, "BUG: bad node type in freenode()"); abort(); } } } +#if 0 DPUTS(size != ((char *) nodes) - ((char *) a), "BUG: size wrong in freenode()"); +#endif zfree(a, size); } diff --git a/Src/zsh.h b/Src/zsh.h index c34b2bd53..2cf632abf 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -392,6 +392,7 @@ struct node { #define NT_EMPTY 0 #define NT_NODE 1 #define NT_STR 2 +#define NT_PAT 3 #define NT_LIST 4 #define NT_ARR 8 @@ -502,6 +503,7 @@ struct cond { int type; /* can be cond_type, or a single */ /* letter (-a, -b, ...) */ void *left, *right; + Patprog prog; /* compiled pattern for `==' and `!=' */ }; #define COND_NOT 0 @@ -555,18 +557,11 @@ struct forcmd { /* for/select */ struct casecmd { /* Cmd->args contains word to test */ int ntype; /* node type */ - char **pats; + char **pats; /* pattern strings */ + Patprog *progs; /* compiled patterns (on demand) */ List *lists; /* list to execute */ }; - -/* A command like "if foo then bar elif baz then fubar else fooble" */ -/* generates a tree like: */ -/* */ -/* struct ifcmd a = { next = &b, ifl = "foo", thenl = "bar" } */ -/* struct ifcmd b = { next = &c, ifl = "baz", thenl = "fubar" } */ -/* struct ifcmd c = { next = NULL, ifl = NULL, thenl = "fooble" } */ - struct ifcmd { int ntype; /* node type */ List *ifls; @@ -974,6 +969,7 @@ struct patprog { #define PAT_PURES 0x0020 /* Pattern is a pure string: set internally */ #define PAT_STATIC 0x0040 /* Don't copy pattern to heap as per default */ #define PAT_SCAN 0x0080 /* Scanning, so don't try must-match test */ +#define PAT_ZDUP 0x0100 /* Copy pattern in real memory */ /* Globbing flags: lower 8 bits gives approx count */ #define GF_LCMATCHUC 0x0100 @@ -981,6 +977,12 @@ struct patprog { #define GF_BACKREF 0x0400 #define GF_MATCHREF 0x0800 +/* Dummy Patprog pointers. Used mainly in executions trees, but the + * pattern code needs to knwo about it, too. */ + +#define dummy_patprog1 ((Patprog) 1) +#define dummy_patprog2 ((Patprog) 2) + /* node used in parameter hash table (paramtab) */ struct param { |