diff options
Diffstat (limited to 'Src/loop.c')
-rw-r--r-- | Src/loop.c | 380 |
1 files changed, 271 insertions, 109 deletions
diff --git a/Src/loop.c b/Src/loop.c index 5fbf2b841..d0280207a 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -43,47 +43,79 @@ int contflag; /* # of break levels */ /**/ -int breaks; - +mod_export int breaks; + /**/ int -execfor(Cmd cmd) +execfor(Estate state, int do_exec) { - List list; - Forcmd node; - char *str; - int val; - LinkList args; + Wordcode end, loop; + wordcode code = state->pc[-1]; + int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; + char *name, *str, *cond = NULL, *advance = NULL; + zlong val = 0; + LinkList args = NULL; + + name = ecgetstr(state, EC_NODUP, NULL); + end = state->pc + WC_FOR_SKIP(code); - node = cmd->u.forcmd; - args = cmd->args; - if (node->condition) { - str = node->name; + if (iscond) { + str = dupstring(name); singsub(&str); + if (isset(XTRACE)) { + char *str2 = dupstring(str); + untokenize(str2); + printprompt4(); + fprintf(xtrerr, "%s\n", str2); + fflush(xtrerr); + } if (!errflag) matheval(str); - if (errflag) + if (errflag) { + state->pc = end; return lastval = errflag; - } else if (!node->inflag) { + } + cond = ecgetstr(state, EC_NODUP, &ctok); + advance = ecgetstr(state, EC_NODUP, &atok); + } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) { + int htok = 0; + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; + return 0; + } + if (htok) + execsubst(args); + } else { char **x; args = newlinklist(); for (x = pparams; *x; x++) - addlinknode(args, ztrdup(*x)); + addlinknode(args, dupstring(*x)); } lastval = 0; loops++; pushheap(); + cmdpush(CS_FOR); + loop = state->pc; for (;;) { - if (node->condition) { - str = dupstring(node->condition); - singsub(&str); + if (iscond) { + if (ctok) { + str = dupstring(cond); + singsub(&str); + } else + str = cond; if (!errflag) { while (iblank(*str)) str++; - if (*str) - val = matheval(str); - else + if (*str) { + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s\n", str); + fflush(xtrerr); + } + val = mathevali(str); + } else val = 1; } if (errflag) { @@ -95,22 +127,36 @@ execfor(Cmd cmd) if (!val) break; } else { - str = (char *) ugetnode(args); - if (!str) + if (!args || !(str = (char *) ugetnode(args))) break; - setsparam(node->name, ztrdup(str)); + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s=%s\n", name, str); + fflush(xtrerr); + } + setsparam(name, ztrdup(str)); } - list = (List) dupstruct(node->list); - execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args)); + state->pc = loop; + execlist(state, 1, do_exec && args && empty(args)); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } - if (node->condition && !errflag) { - str = dupstring(node->advance); - singsub(&str); + if (retflag) + break; + if (iscond && !errflag) { + if (atok) { + str = dupstring(advance); + singsub(&str); + } else + str = advance; + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s\n", str); + fflush(xtrerr); + } if (!errflag) matheval(str); } @@ -123,44 +169,67 @@ execfor(Cmd cmd) freeheap(); } popheap(); + cmdpop(); loops--; + state->pc = end; return lastval; } /**/ int -execselect(Cmd cmd) +execselect(Estate state, int do_exec) { - List list; - Forcmd node; - char *str, *s; - LinkList args; + Wordcode end, loop; + wordcode code = state->pc[-1]; + char *str, *s, *name; LinkNode n; - int i; + int i, usezle; FILE *inp; + size_t more; + LinkList args; + + end = state->pc + WC_FOR_SKIP(code); + name = ecgetstr(state, EC_NODUP, NULL); - node = cmd->u.forcmd; - args = cmd->args; - if (!node->inflag) { + if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { char **x; args = newlinklist(); for (x = pparams; *x; x++) - addlinknode(args, ztrdup(*x)); + addlinknode(args, dupstring(*x)); + } else { + int htok = 0; + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; + return 0; + } + if (htok) + execsubst(args); } - if (empty(args)) + if (!args || empty(args)) { + state->pc = end; return 1; + } loops++; lastval = 0; pushheap(); - inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r"); - selectlist(args); + cmdpush(CS_SELECT); + usezle = interact && SHTTY != -1 && isset(USEZLE); + inp = fdopen(dup(usezle ? SHTTY : 0), "r"); + more = selectlist(args, 0); + loop = state->pc; for (;;) { for (;;) { if (empty(bufstack)) { - if (interact && SHTTY != -1 && isset(USEZLE)) { + if (usezle) { + int oef = errflag; + isfirstln = 1; str = (char *)zleread(prompt3, NULL, 0); + if (errflag) + str = NULL; + errflag = oef; } else { str = promptexpand(prompt3, 0, NULL, NULL); zputs(str, stderr); @@ -181,7 +250,7 @@ execselect(Cmd cmd) *s = '\0'; if (*str) break; - selectlist(args); + more = selectlist(args, more); } setsparam("REPLY", ztrdup(str)); i = atoi(str); @@ -194,9 +263,9 @@ execselect(Cmd cmd) else str = ""; } - setsparam(node->name, ztrdup(str)); - list = (List) dupstruct(node->list); - execlist(list, 1, 0); + setsparam(name, ztrdup(str)); + state->pc = loop; + execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; @@ -204,21 +273,23 @@ execselect(Cmd cmd) break; contflag = 0; } - if (errflag) + if (retflag || errflag) break; } done: + cmdpop(); popheap(); fclose(inp); loops--; + state->pc = end; return lastval; } /* And this is used to print select lists. */ /**/ -static void -selectlist(LinkList l) +size_t +selectlist(LinkList l, size_t start) { size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct; LinkNode n; @@ -226,7 +297,7 @@ selectlist(LinkList l) trashzle(); ct = countlinknodes(l); - ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **)); + ap = arr = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char **)); for (n = (LinkNode) firstnode(l); n; incnode(n)) *ap++ = (char *)getdata(n); @@ -245,7 +316,7 @@ selectlist(LinkList l) else fw = (columns - 1) / fct; colsz = (ct + fct - 1) / fct; - for (t1 = 0; t1 != colsz; t1++) { + for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) { ap = arr + t1; do { int t2 = strlen(*ap) + 2, t3; @@ -271,70 +342,86 @@ selectlist(LinkList l) } while (*ap);*/ fflush(stderr); + + return t1 < colsz ? t1 : 0; } /**/ int -execwhile(Cmd cmd) +execwhile(Estate state, int do_exec) { - List list; - struct whilecmd *node; - int olderrexit, oldval; + Wordcode end, loop; + wordcode code = state->pc[-1]; + int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL); + end = state->pc + WC_WHILE_SKIP(code); olderrexit = noerrexit; - node = cmd->u.whilecmd; oldval = 0; pushheap(); + cmdpush(isuntil ? CS_UNTIL : CS_WHILE); loops++; + loop = state->pc; for (;;) { - list = (List) dupstruct(node->cont); + state->pc = loop; noerrexit = 1; - execlist(list, 1, 0); + execlist(state, 1, 0); noerrexit = olderrexit; - if (!((lastval == 0) ^ node->cond)) { + if (!((lastval == 0) ^ isuntil)) { if (breaks) breaks--; lastval = oldval; break; } - list = (List) dupstruct(node->loop); - execlist(list, 1, 0); + if (retflag) { + lastval = oldval; + break; + } + execlist(state, 1, 0); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } - freeheap(); if (errflag) { lastval = 1; break; } + if (retflag) + break; + freeheap(); oldval = lastval; } + cmdpop(); popheap(); loops--; + state->pc = end; return lastval; } /**/ int -execrepeat(Cmd cmd) +execrepeat(Estate state, int do_exec) { - List list; - int count; + Wordcode end, loop; + wordcode code = state->pc[-1]; + int count, htok = 0; + char *tmp; + + end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; - if (empty(cmd->args) || nextnode(firstnode(cmd->args))) { - zerr("bad argument for repeat", NULL, 0); - return 1; - } - count = atoi(peekfirst(cmd->args)); + tmp = ecgetstr(state, EC_DUPTOK, &htok); + if (htok) + singsub(&tmp); + count = atoi(tmp); pushheap(); + cmdpush(CS_REPEAT); loops++; - while (count--) { - list = (List) dupstruct(cmd->u.list); - execlist(list, 1, 0); + loop = state->pc; + while (count-- > 0) { + state->pc = loop; + execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; @@ -346,76 +433,151 @@ execrepeat(Cmd cmd) lastval = 1; break; } + if (retflag) + break; } + cmdpop(); popheap(); loops--; + state->pc = end; return lastval; } /**/ int -execif(Cmd cmd) +execif(Estate state, int do_exec) { - struct ifcmd *node; - int olderrexit; - List *i, *t; + Wordcode end, next; + wordcode code = state->pc[-1]; + int olderrexit, s = 0, run = 0; olderrexit = noerrexit; - node = cmd->u.ifcmd; - i = node->ifls; - t = node->thenls; + end = state->pc + WC_IF_SKIP(code); if (!noerrexit) noerrexit = 1; - while (*i) { - execlist(*i, 1, 0); - if (!lastval) + while (state->pc < end) { + code = *state->pc++; + if (wc_code(code) != WC_IF || + (run = (WC_IF_TYPE(code) == WC_IF_ELSE))) { + if (run) + run = 2; break; - i++; - t++; + } + next = state->pc + WC_IF_SKIP(code); + cmdpush(s ? CS_ELIF : CS_IF); + execlist(state, 1, 0); + cmdpop(); + if (!lastval) { + run = 1; + break; + } + if (retflag) + break; + s = 1; + state->pc = next; } noerrexit = olderrexit; - if (*t) - execlist(*t, 1, cmd->flags & CFLAG_EXEC); - else + if (run) { + cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN)); + execlist(state, 1, do_exec); + cmdpop(); + } else lastval = 0; + state->pc = end; return lastval; } /**/ int -execcase(Cmd cmd) +execcase(Estate state, int do_exec) { - struct casecmd *node; - char *word; - List *l; - char **p; + Wordcode end, next; + wordcode code = state->pc[-1]; + char *word, *pat; + int npat, save; + Patprog *spprog, pprog; - node = cmd->u.casecmd; - l = node->lists; - p = node->pats; + end = state->pc + WC_CASE_SKIP(code); - word = *p++; + word = ecgetstr(state, EC_DUP, NULL); singsub(&word); untokenize(word); lastval = 0; - if (node) { - while (*p) { - char *pat = *p + 1; + cmdpush(CS_CASE); + while (state->pc < end) { + code = *state->pc++; + if (wc_code(code) != WC_CASE) + break; + + pat = NULL; + pprog = NULL; + save = 0; + npat = state->pc[1]; + spprog = state->prog->pats + npat; + + next = state->pc + WC_CASE_SKIP(code); + + if (isset(XTRACE)) { + char *pat2, *opat; + + opat = pat = ecgetstr(state, EC_DUP, NULL); singsub(&pat); - if (matchpat(word, pat)) { - do { - execlist(*l++, 1, **p == ';' && (cmd->flags & CFLAG_EXEC)); - } while(**p++ == '&' && *p); - break; + save = (!(state->prog->flags & EF_HEAP) && + !strcmp(pat, opat) && *spprog != dummy_patprog2); + + pat2 = dupstring(pat); + untokenize(pat2); + printprompt4(); + fprintf(xtrerr, "case %s (%s)\n", word, pat2); + fflush(xtrerr); + state->pc++; + } else + state->pc += 2; + + if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) + pprog = *spprog; + + if (!pprog) { + if (!pat) { + char *opat; + int htok = 0; + + opat = pat = dupstring(ecrawstr(state->prog, + state->pc - 2, &htok)); + if (htok) + singsub(&pat); + save = (!(state->prog->flags & EF_HEAP) && + !strcmp(pat, opat) && *spprog != dummy_patprog2); } - p++; - l++; + if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) + zerr("bad pattern: %s", pat, 0); + else if (save) + *spprog = pprog; } + if (pprog && pattry(pprog, word)) { + execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && + do_exec)); + while (!retflag && wc_code(code) == WC_CASE && + WC_CASE_TYPE(code) == WC_CASE_AND) { + state->pc = next; + code = *state->pc; + state->pc += 3; + next = state->pc + WC_CASE_SKIP(code) - 1; + execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && + do_exec)); + } + break; + } else + state->pc = next; } + cmdpop(); + + state->pc = end; + return lastval; } - |