/*
 * $Id: loop.c,v 3.1.0.2 1996/12/05 03:59:45 hzoli Exp $
 *
 * loop.c - loop execution
 *
 * This file is part of zsh, the Z shell.
 *
 * Copyright (c) 1992-1996 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.h"

/**/
int
execfor(Cmd cmd)
{
    List list;
    Forcmd node;
    char *str;
    int val;
    LinkList args;

    lastval = 0;
    node = cmd->u.forcmd;
    args = cmd->args;
    if (node->condition) {
	str = node->name;
	singsub(&str);
	if (!errflag)
	    matheval(str);
	if (errflag)
	    return lastval = errflag;
    } else if (!node->inflag) {
	char **x;

	args = newlinklist();
	for (x = pparams; *x; x++)
	    addlinknode(args, ztrdup(*x));
    }
    loops++;
    pushheap();
    for (;;) {
	if (node->condition) {
	    str = dupstring(node->condition);
	    singsub(&str);
	    if (!errflag) {
		while (iblank(*str))
		    str++;
		if (*str)
		    val = matheval(str);
		else
		    val = 1;
	    }
	    if (errflag) {
		if (breaks)
		    breaks--;
		lastval = 1;
		break;
	    }
	    if (!val)
		break;
	} else {
	    str = (char *) ugetnode(args);
	    if (!str)
		break;
	    setsparam(node->name, ztrdup(str));
	}
	list = (List) dupstruct(node->list);
	execlist(list, 1, (cmd->flags & CFLAG_EXEC) && empty(args));
	if (breaks) {
	    breaks--;
	    if (breaks || !contflag)
		break;
	    contflag = 0;
	}
	if (node->condition && !errflag) {
	    str = dupstring(node->advance);
	    singsub(&str);
	    if (!errflag)
		matheval(str);
	}
	if (errflag) {
	    if (breaks)
		breaks--;
	    lastval = 1;
	    break;
	}
	freeheap();
    }
    popheap();
    loops--;
    return lastval;
}

/**/
int
execselect(Cmd cmd)
{
    List list;
    Forcmd node;
    char *str, *s;
    LinkList args;
    LinkNode n;
    int i;
    FILE *inp;

    node = cmd->u.forcmd;
    args = cmd->args;
    if (!node->inflag) {
	char **x;

	args = newlinklist();
	for (x = pparams; *x; x++)
	    addlinknode(args, ztrdup(*x));
    }
    if (empty(args))
	return 1;
    loops++;
    lastval = 0;
    pushheap();
    inp = fdopen(dup((SHTTY == -1) ? 0 : SHTTY), "r");
    for (;;) {
	do {
	    selectlist(args);
	    if (empty(bufstack)) {
	    	if (interact && SHTTY != -1 && isset(USEZLE))
		    str = (char *)zleread(prompt3, NULL);
	    	else {
		    int pptlen;
		    str = putprompt(prompt3, &pptlen, NULL, 1);
		    fwrite(str, pptlen, 1, 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';
	}
	while (!*str);
	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(node->name, ztrdup(str));
	list = (List) dupstruct(node->list);
	execlist(list, 1, 0);
	freeheap();
	if (breaks) {
	    breaks--;
	    if (breaks || !contflag)
		break;
	    contflag = 0;
	}
	if (errflag)
	    break;
    }
  done:
    popheap();
    fclose(inp);
    loops--;
    return lastval;
}

/* And this is used to print select lists. */

/**/
void
selectlist(LinkList l)
{
    size_t longest = 1, fct, fw = 0, colsz, t0, t1, ct;
    LinkNode n;
    char **arr, **ap;

    trashzle();
    ct = countlinknodes(l);
    ap = arr = (char **)alloc((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 = 0; t1 != colsz; t1++) {
	ap = arr + t1;
	do {
	    int t2 = strlen(*ap) + 2, 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);
}

/**/
int
execwhile(Cmd cmd)
{
    List list;
    struct whilecmd *node;
    int olderrexit, oldval;

    olderrexit = noerrexit;
    node = cmd->u.whilecmd;
    lastval = 0;
    pushheap();
    loops++;
    for (;;) {
	oldval = lastval;
	list = (List) dupstruct(node->cont);
	noerrexit = 1;
	execlist(list, 1, 0);
	noerrexit = olderrexit;
	if (!((lastval == 0) ^ node->cond)) {
	    if (breaks)
		breaks--;
	    lastval = oldval;
	    break;
	}
	list = (List) dupstruct(node->loop);
	execlist(list, 1, 0);
	if (breaks) {
	    breaks--;
	    if (breaks || !contflag)
		break;
	    contflag = 0;
	}
	freeheap();
	if (errflag) {
	    lastval = 1;
	    break;
	}
    }
    popheap();
    loops--;
    return lastval;
}

/**/
int
execrepeat(Cmd cmd)
{
    List list;
    int count;

    lastval = 0;
    if (empty(cmd->args) || nextnode(firstnode(cmd->args))) {
	zerr("bad argument for repeat", NULL, 0);
	return 1;
    }
    count = atoi(peekfirst(cmd->args));
    pushheap();
    loops++;
    while (count--) {
	list = (List) dupstruct(cmd->u.list);
	execlist(list, 1, 0);
	freeheap();
	if (breaks) {
	    breaks--;
	    if (breaks || !contflag)
		break;
	    contflag = 0;
	}
	if (errflag) {
	    lastval = 1;
	    break;
	}
    }
    popheap();
    loops--;
    return lastval;
}

/**/
int
execif(Cmd cmd)
{
    struct ifcmd *node;
    int olderrexit;
    List *i, *t;

    olderrexit = noerrexit;
    node = cmd->u.ifcmd;
    i = node->ifls;
    t = node->thenls;

    if (!noerrexit)
	noerrexit = 1;
    while (*i) {
	execlist(*i, 1, 0);
	if (!lastval)
	    break;
	i++;
	t++;
    }
    noerrexit = olderrexit;

    if (*t)
	execlist(*t, 1, cmd->flags & CFLAG_EXEC);
    else
	lastval = 0;

    return lastval;
}

/**/
int
execcase(Cmd cmd)
{
    struct casecmd *node;
    char *word;
    LinkList args;
    List *l;
    char **p;

    node = cmd->u.casecmd;
    args = cmd->args;
    l = node->lists;
    p = node->pats;

    lastval = 0;
    if (firstnode(args) && nextnode(firstnode(args))) {
	zerr("too many arguments to case", NULL, 0);
	return 1;
    }
    if (empty(args))
	word = dupstring("");
    else
	word = (char *)peekfirst(args);

    if (node) {
	while (*p) {
	    singsub(p);
	    if (matchpat(word, *p))
		break;
	    p++;
	    l++;
	}
	if (*l)
	    execlist(*l, 1, cmd->flags & CFLAG_EXEC);
    }
    return lastval;
}

