diff -r 000000000000 -r 2e3d3ce01487 openenvutils/commandshell/shell/src/loop.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openenvutils/commandshell/shell/src/loop.c Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,691 @@ +// loop.c - loop execution +// +// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. +// +/* + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ +#include "zsh.mdh" +#include "loop.pro" + +#ifdef __SYMBIAN32__ +#ifdef __WINSCW__ +#pragma warn_unusedarg off +#pragma warn_possunwant off +#endif//__WINSCW__ +#endif//__SYMBIAN32__ + +/* # of nested loops we are in */ + +/**/ +int loops; + +/* # of continue levels */ + +/**/ +mod_export int contflag; + +/* # of break levels */ + +/**/ +mod_export int breaks; + +/**/ +int +execfor(Estate state, int do_exec) +{ + Wordcode end, loop; + wordcode code = state->pc[-1]; + int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; + int last = 0; + char *name, *str, *cond = NULL, *advance = NULL; + zlong val = 0; + LinkList vars = NULL, args = NULL; + + end = state->pc + WC_FOR_SKIP(code); + + if (iscond) { + str = dupstring(ecgetstr(state, EC_NODUP, NULL)); + 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) { + state->pc = end; + return lastval = errflag; + } + cond = ecgetstr(state, EC_NODUP, &ctok); + advance = ecgetstr(state, EC_NODUP, &atok); + } else { + vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); + + 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, dupstring(*x)); + } + } + lastval = 0; + loops++; + pushheap(); + cmdpush(CS_FOR); + loop = state->pc; + while (!last) { + if (iscond) { + if (ctok) { + str = dupstring(cond); + singsub(&str); + } else + str = cond; + if (!errflag) { + while (iblank(*str)) + str++; + if (*str) { + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s\n", str); + fflush(xtrerr); + } + val = mathevali(str); + } else + val = 1; + } + if (errflag) { + if (breaks) + breaks--; + lastval = 1; + break; + } + if (!val) + break; + } else { + LinkNode node; + int count = 0; + for (node = firstnode(vars); node; incnode(node)) + { + name = (char *)getdata(node); + if (!args || !(str = (char *) ugetnode(args))) + { + if (count) { + str = ""; + last = 1; + } else + break; + } + if (isset(XTRACE)) { + printprompt4(); + fprintf(xtrerr, "%s=%s\n", name, str); + fflush(xtrerr); + } + setsparam(name, ztrdup(str)); + count++; + } + if (!count) + break; + } + state->pc = loop; + execlist(state, 1, do_exec && args && empty(args)); + if (breaks) { + breaks--; + if (breaks || !contflag) + break; + contflag = 0; + } + 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); + } + if (errflag) { + if (breaks) + breaks--; + lastval = 1; + break; + } + freeheap(); + } + popheap(); + cmdpop(); + loops--; + state->pc = end; + return lastval; +} + +/**/ +int +execselect(Estate state, UNUSED(int do_exec)) +{ + Wordcode end, loop; + wordcode code = state->pc[-1]; + char *str, *s, *name; + LinkNode n; + int i, usezle; + FILE *inp; + size_t more; + LinkList args; + + end = state->pc + WC_FOR_SKIP(code); + name = ecgetstr(state, EC_NODUP, NULL); + + if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { + char **x; + + args = newlinklist(); + for (x = pparams; *x; 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 (!args || empty(args)) { + state->pc = end; + return 1; + } + loops++; + lastval = 0; + pushheap(); + 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 (usezle) { + int oef = errflag; + + isfirstln = 1; + str = (char *)zleread(&prompt3, NULL, 0, ZLCON_SELECT); + if (errflag) + str = NULL; + errflag = oef; + } else { + str = promptexpand(prompt3, 0, NULL, NULL); + zputs(str, stderr); + free(str); + fflush(stderr); + str = fgets(zalloc(256), 256, inp); + } + } else + str = (char *)getlinknode(bufstack); + if (!str || errflag) { + if (breaks) + breaks--; + fprintf(stderr, "\n"); + fflush(stderr); + goto done; + } + if ((s = strchr(str, '\n'))) + *s = '\0'; + if (*str) + break; + more = selectlist(args, more); + } + setsparam("REPLY", ztrdup(str)); + i = atoi(str); + if (!i) + str = ""; + else { + for (i--, n = firstnode(args); n && i; incnode(n), i--); + if (n) + str = (char *) getdata(n); + else + str = ""; + } + setsparam(name, ztrdup(str)); + state->pc = loop; + execlist(state, 1, 0); + freeheap(); + if (breaks) { + breaks--; + if (breaks || !contflag) + break; + contflag = 0; + } + if (retflag || errflag) + break; + } + done: + cmdpop(); + popheap(); + fclose(inp); + loops--; + state->pc = end; + return lastval; +} + +/* And this is used to print select lists. */ + +/**/ +size_t +selectlist(LinkList l, size_t start) +{ + size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct; + LinkNode n; + char **arr, **ap; + + trashzle(); + ct = countlinknodes(l); + ap = arr = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char **)); + + for (n = (LinkNode) firstnode(l); n; incnode(n)) + *ap++ = (char *)getdata(n); + *ap = NULL; + for (ap = arr; *ap; ap++) + if (strlen(*ap) > longest) + longest = strlen(*ap); + t0 = ct; + longest++; + while (t0) + t0 /= 10, longest++; + /* to compensate for added ')' */ + fct = (columns - 1) / (longest + 3); + if (fct == 0) + fct = 1; + else + fw = (columns - 1) / fct; + colsz = (ct + fct - 1) / fct; + for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) { + ap = arr + t1; + do { + size_t t2 = strlen(*ap) + 2; + int t3; + + fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap); + while (t3) + t2++, t3 /= 10; + for (; t2 < fw; t2++) + fputc(' ', stderr); + for (t0 = colsz; t0 && *ap; t0--, ap++); + } + while (*ap); + fputc('\n', stderr); + } + + /* Below is a simple attempt at doing it the Korn Way.. + ap = arr; + t0 = 0; + do { + t0++; + fprintf(stderr,"%d) %s\n",t0,*ap); + ap++; + } + while (*ap);*/ + fflush(stderr); + + return t1 < colsz ? t1 : 0; +} + +/**/ +int +execwhile(Estate state, UNUSED(int do_exec)) +{ + 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; + oldval = 0; + pushheap(); + cmdpush(isuntil ? CS_UNTIL : CS_WHILE); + loops++; + loop = state->pc; + + if (loop[0] == WC_END && loop[1] == WC_END) { + + /* This is an empty loop. Make sure the signal handler sets the + * flags and then just wait for someone hitting ^C. */ + + int old_simple_pline = simple_pline; + + simple_pline = 1; + + while (!breaks) + ; + breaks--; + + simple_pline = old_simple_pline; + } else + for (;;) { + state->pc = loop; + noerrexit = 1; + execlist(state, 1, 0); + noerrexit = olderrexit; + if (!((lastval == 0) ^ isuntil)) { + if (breaks) + breaks--; + lastval = oldval; + break; + } + if (retflag) { + lastval = oldval; + break; + } + execlist(state, 1, 0); + if (breaks) { + breaks--; + if (breaks || !contflag) + break; + contflag = 0; + } + if (errflag) { + lastval = 1; + break; + } + if (retflag) + break; + freeheap(); + oldval = lastval; + } + cmdpop(); + popheap(); + loops--; + state->pc = end; + return lastval; +} + +/**/ +int +execrepeat(Estate state, UNUSED(int do_exec)) +{ + Wordcode end, loop; + wordcode code = state->pc[-1]; + int count, htok = 0; + char *tmp; + + end = state->pc + WC_REPEAT_SKIP(code); + + lastval = 0; + tmp = ecgetstr(state, EC_DUPTOK, &htok); + if (htok) + singsub(&tmp); + count = atoi(tmp); + pushheap(); + cmdpush(CS_REPEAT); + loops++; + loop = state->pc; + while (count-- > 0) { + state->pc = loop; + execlist(state, 1, 0); + freeheap(); + if (breaks) { + breaks--; + if (breaks || !contflag) + break; + contflag = 0; + } + if (errflag) { + lastval = 1; + break; + } + if (retflag) + break; + } + cmdpop(); + popheap(); + loops--; + state->pc = end; + return lastval; +} + +/**/ +int +execif(Estate state, int do_exec) +{ + Wordcode end, next; + wordcode code = state->pc[-1]; + int olderrexit, s = 0, run = 0; + + olderrexit = noerrexit; + end = state->pc + WC_IF_SKIP(code); + + if (!noerrexit) + noerrexit = 1; + 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; + } + 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 (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(Estate state, int do_exec) +{ + Wordcode end, next; + wordcode code = state->pc[-1]; + char *word, *pat; + int npat, save; + Patprog *spprog, pprog; + + end = state->pc + WC_CASE_SKIP(code); + + word = ecgetstr(state, EC_DUP, NULL); + singsub(&word); + untokenize(word); + lastval = 0; + + 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; + + pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL)); + singsub(&pat); + 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 += 2; + + if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) + pprog = *spprog; + + if (!pprog) { + if (!pat) { + char *opat; + int htok = 0; + + pat = dupstring(opat = ecrawstr(state->prog, + state->pc - 2, &htok)); + if (htok) + singsub(&pat); + save = (!(state->prog->flags & EF_HEAP) && + !strcmp(pat, opat) && *spprog != dummy_patprog2); + } + 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) - 2; + execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && + do_exec)); + } + break; + } else + state->pc = next; + } + cmdpop(); + + state->pc = end; + + return lastval; +} + +/* + * Errflag from `try' block, may be reset in `always' block. + * Accessible from an integer parameter, so needs to be a zlong. + */ + +/**/ +zlong +try_errflag = -1; + +/**/ +int +exectry(Estate state, int do_exec) +{ + Wordcode end, always; + int endval; + int save_retflag, save_breaks, save_loops, save_contflag; + zlong save_try_errflag; + + end = state->pc + WC_TRY_SKIP(state->pc[-1]); + always = state->pc + 1 + WC_TRY_SKIP(*state->pc); + state->pc++; + pushheap(); + cmdpush(CS_CURSH); + + /* The :try clause */ + execlist(state, 1, do_exec); + + /* Don't record errflag here, may be reset. */ + endval = lastval; + + freeheap(); + + cmdpop(); + cmdpush(CS_ALWAYS); + + /* The always clause. */ + save_try_errflag = try_errflag; + try_errflag = (zlong)errflag; + errflag = 0; + save_retflag = retflag; + retflag = 0; + save_breaks = breaks; + breaks = 0; + save_loops = loops; + loops = 0; + save_contflag = contflag; + contflag = 0; + + state->pc = always; + execlist(state, 1, do_exec); + + errflag = try_errflag ? 1 : 0; + try_errflag = save_try_errflag; + retflag = save_retflag; + breaks = save_breaks; + loops = save_loops; + contflag = save_contflag; + + cmdpop(); + popheap(); + state->pc = end; + + return endval; +}