about summary refs log tree commit diff
path: root/Src/loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/loop.c')
-rw-r--r--Src/loop.c283
1 files changed, 174 insertions, 109 deletions
diff --git a/Src/loop.c b/Src/loop.c
index b8e7f956f..f2958114c 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -47,15 +47,20 @@ mod_export int breaks;
 
 /**/
 int
-execfor(Cmd cmd, LinkList args, int flags)
+execfor(Estate state, int do_exec)
 {
-    Forcmd node;
-    char *str;
+    Wordcode end, loop;
+    wordcode code = state->pc[-1];
+    int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND);
+    char *name, *str, *cond, *advance;
     zlong val = 0;
+    LinkList args;
 
-    node = cmd->u.forcmd;
-    if (node->condition) {
-	str = dupstring(node->name);
+    name = ecgetstr(state, 0);
+    end = state->pc + WC_FOR_SKIP(code);
+
+    if (iscond) {
+	str = dupstring(name);
 	singsub(&str);
 	if (isset(XTRACE)) {
 	    char *str2 = dupstring(str);
@@ -66,9 +71,19 @@ execfor(Cmd cmd, LinkList args, int flags)
 	}
 	if (!errflag)
 	    matheval(str);
-	if (errflag)
+	if (errflag) {
+	    state->pc = end;
 	    return lastval = errflag;
-    } else if (!node->inflag) {
+	}
+	cond = ecgetstr(state, 0);
+	advance = ecgetstr(state, 0);
+    } else if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
+	if (!(args = ecgetlist(state, *state->pc++, 1))) {
+	    state->pc = end;
+	    return 0;
+	}
+	execsubst(args);
+    } else {
 	char **x;
 
 	args = newlinklist();
@@ -79,9 +94,10 @@ execfor(Cmd cmd, LinkList args, int flags)
     loops++;
     pushheap();
     cmdpush(CS_FOR);
+    loop = state->pc;
     for (;;) {
-	if (node->condition) {
-	    str = dupstring(node->condition);
+	if (iscond) {
+	    str = dupstring(cond);
 	    singsub(&str);
 	    if (!errflag) {
 		while (iblank(*str))
@@ -109,21 +125,21 @@ execfor(Cmd cmd, LinkList args, int flags)
 		break;
 	    if (isset(XTRACE)) {
 		printprompt4();
-		fprintf(stderr, "%s=%s\n", node->name, str);
+		fprintf(stderr, "%s=%s\n", name, str);
 		fflush(stderr);
 	    }
-	    setsparam(node->name, ztrdup(str));
+	    setsparam(name, ztrdup(str));
 	}
-	execlist(node->list, 1,
-		 (flags & CFLAG_EXEC) && args && 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);
+	if (iscond && !errflag) {
+	    str = dupstring(advance);
 	    if (isset(XTRACE)) {
 		printprompt4();
 		fprintf(stderr, "%s\n", str);
@@ -149,25 +165,37 @@ execfor(Cmd cmd, LinkList args, int flags)
 
 /**/
 int
-execselect(Cmd cmd, LinkList args, int flags)
+execselect(Estate state, int do_exec)
 {
-    Forcmd node;
-    char *str, *s;
+    Wordcode end, loop;
+    wordcode code = state->pc[-1];
+    char *str, *s, *name;
     LinkNode n;
     int i, usezle;
     FILE *inp;
     size_t more;
+    LinkList args;
 
-    node = cmd->u.forcmd;
-    if (!node->inflag) {
+    end = state->pc + WC_FOR_SKIP(code);
+    name = ecgetstr(state, 0);
+
+    if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) {
 	char **x;
 
 	args = newlinklist();
 	for (x = pparams; *x; x++)
 	    addlinknode(args, dupstring(*x));
+    } else {
+	if (!(args = ecgetlist(state, *state->pc++, 1))) {
+	    state->pc = end;
+	    return 0;
+	}
+	execsubst(args);
     }
-    if (!args || empty(args))
+    if (!args || empty(args)) {
+	state->pc = end;
 	return 1;
+    }
     loops++;
     lastval = 0;
     pushheap();
@@ -175,6 +203,7 @@ execselect(Cmd cmd, LinkList args, int flags)
     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)) {
@@ -219,8 +248,9 @@ execselect(Cmd cmd, LinkList args, int flags)
 	    else
 		str = "";
 	}
-	setsparam(node->name, ztrdup(str));
-	execlist(node->list, 1, 0);
+	setsparam(name, ztrdup(str));
+	state->pc = loop;
+	execlist(state, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -236,6 +266,7 @@ execselect(Cmd cmd, LinkList args, int flags)
     popheap();
     fclose(inp);
     loops--;
+    state->pc = end;
     return lastval;
 }
 
@@ -302,28 +333,31 @@ selectlist(LinkList l, size_t start)
 
 /**/
 int
-execwhile(Cmd cmd, LinkList args, int flags)
+execwhile(Estate state, int do_exec)
 {
-    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(node->cond ? CS_UNTIL : CS_WHILE);
+    cmdpush(isuntil ? CS_UNTIL : CS_WHILE);
     loops++;
+    loop = state->pc;
     for (;;) {
+	state->pc = loop;
 	noerrexit = 1;
-	execlist(node->cont, 1, 0);
+	execlist(state, 1, 0);
 	noerrexit = olderrexit;
-	if (!((lastval == 0) ^ node->cond)) {
+	if (!((lastval == 0) ^ isuntil)) {
 	    if (breaks)
 		breaks--;
 	    lastval = oldval;
 	    break;
 	}
-	execlist(node->loop, 1, 0);
+	execlist(state, 1, 0);
 	if (breaks) {
 	    breaks--;
 	    if (breaks || !contflag)
@@ -345,21 +379,26 @@ execwhile(Cmd cmd, LinkList args, int flags)
 
 /**/
 int
-execrepeat(Cmd cmd, LinkList args, int flags)
+execrepeat(Estate state, int do_exec)
 {
+    Wordcode end, loop;
+    wordcode code = state->pc[-1];
     int count;
+    char *tmp;
+
+    end = state->pc + WC_REPEAT_SKIP(code);
 
     lastval = 0;
-    if (!args || empty(args) || nextnode(firstnode(args))) {
-	zerr("bad argument for repeat", NULL, 0);
-	return 1;
-    }
-    count = atoi(peekfirst(args));
+    tmp = ecgetstr(state, 1);
+    singsub(&tmp);
+    count = atoi(tmp);
     pushheap();
     cmdpush(CS_REPEAT);
     loops++;
+    loop = state->pc;
     while (count-- > 0) {
-	execlist(cmd->u.list, 1, 0);
+	state->pc = loop;
+	execlist(state, 1, 0);
 	freeheap();
 	if (breaks) {
 	    breaks--;
@@ -375,114 +414,140 @@ execrepeat(Cmd cmd, LinkList args, int flags)
     cmdpop();
     popheap();
     loops--;
+    state->pc = end;
     return lastval;
 }
 
 /**/
 int
-execif(Cmd cmd, LinkList args, int flags)
+execif(Estate state, int do_exec)
 {
-    struct ifcmd *node;
-    int olderrexit, s = 0;
-    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) {
+    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(*i, 1, 0);
+	execlist(state, 1, 0);
 	cmdpop();
-	if (!lastval)
+	if (!lastval) {
+	    run = 1;
 	    break;
+	}
 	s = 1;
-	i++;
-	t++;
+	state->pc = next;
     }
     noerrexit = olderrexit;
 
-    if (*t) {
-	cmdpush(*i ? (s ? CS_ELIFTHEN : CS_IFTHEN) : CS_ELSE);
-	execlist(*t, 1, flags & CFLAG_EXEC);
+    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, LinkList args, int flags)
+execcase(Estate state, int do_exec)
 {
-    struct casecmd *node;
-    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++);
+    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, 1);
     singsub(&word);
     untokenize(word);
     lastval = 0;
 
-    if (node) {
-	cmdpush(CS_CASE);
-	while (*p) {
-	    char *pat = NULL, *opat;
+    cmdpush(CS_CASE);
+    while (state->pc < end) {
+	code = *state->pc++;
+	if (wc_code(code) != WC_CASE)
+	    break;
 
-	    pprog = NULL;
-	    save = 0;
+	pat = NULL;
+	pprog = NULL;
+	save = 0;
+	npat = state->pc[1];
+	spprog = state->prog->pats + npat;
 
-	    if (isset(XTRACE)) {
-		char *pat2;
+	next = state->pc + WC_CASE_SKIP(code);
 
-		opat = pat = dupstring(*p + 1);
-		singsub(&pat);
-		save = (!strcmp(pat, opat) && *pp != dummy_patprog2);
+	if (isset(XTRACE)) {
+	    char *pat2, *opat;
 
-		pat2 = dupstring(pat);
-		untokenize(pat2);
-		printprompt4();
-		fprintf(stderr, "case %s (%s)\n", word, pat2);
-		fflush(stderr);
-	    }
-	    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;
+	    opat = pat = ecgetstr(state, 1);
+	    singsub(&pat);
+	    save = (!state->prog->heap &&
+		    !strcmp(pat, opat) && *spprog != dummy_patprog2);
+
+	    pat2 = dupstring(pat);
+	    untokenize(pat2);
+	    printprompt4();
+	    fprintf(stderr, "case %s (%s)\n", word, pat2);
+	    fflush(stderr);
+	    state->pc++;
+	} else
+	    state->pc += 2;
+
+	if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
+	    pprog = *spprog;
+
+	if (!pprog) {
+	    if (!pat) {
+		char *opat;
+
+		opat = pat = dupstring(ecrawstr(state->prog, state->pc - 2));
+		singsub(&pat);
+		save = (!state->prog->heap &&
+			!strcmp(pat, opat) && *spprog != dummy_patprog2);
 	    }
-	    p++;
-	    pp++;
-	    l++;
+	    if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
+				     NULL)))
+		zerr("bad pattern: %s", pat, 0);
+	    else if (save)
+		*spprog = pprog;
 	}
-	cmdpop();
+	if (pprog && pattry(pprog, word)) {
+	    execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
+				do_exec));
+	    while (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;
 }