openenvutils/commandshell/shell/src/loop.c
changeset 0 2e3d3ce01487
child 4 0fdb7f6b0309
--- /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;
+}