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.c380
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;
 }
-