/*
 * csh - a shell by PJAC
 * cond.c - loops and conditionals
 */

#include "csh.h"
/*
 * for loop processing
 */

do_for(argc, argv)
char	**argv;
{
	struct	lvars	*lp, *xlp;
	int	ac;
	char	**av, **xp;
	char	*savstr;
	struct	forblk	*fp;

	if(argc < 5)
		syn_err();
	ac = argc - 4;
	av = argv + 3;
	if(strcmp(argv[2], "(") || strcmp(argv[argc-1], ")"))
		syn_err();
	if(Cur_ins >= &in_bufs[MAX_INS]){
		puterr("No resources for for loop.\n");
		return(ERR);
	}
	for(lp = Lvars ; lp ; lp = lp->L_next)
		if(strcmp(argv[1], lp->L_name) == 0)
			break;
	if(lp == 0){
		lp = (struct lvars *)mmalloc(sizeof(struct lvars));
		lp->L_name = strsave(argv[1]);
		lp->L_flags = 0;
		lp->L_next = 0;
		if(Lvars == 0)
			Lvars = lp;
		else {
			for(xlp = Lvars ; xlp->L_next ; xlp = xlp->L_next);
			xlp->L_next = lp;
		}
	}
	else if(xp = lp->L_aval){
		while(*xp)
			free(*xp++);
		free( (char *)lp->L_aval);
	}
	lp->L_aval = 0;
	savstr = read_blk("end", (char *)0);
	if(savstr == NULL)
		return(ERR);
	/*
	 * savstr now points to body of loop
	 * build a control block and put it on the input stack
	 */
	fp = (struct forblk *)mmalloc(sizeof(struct forblk));
	fp->F_name = strsave(argv[1]);
	fp->F_argv = (char **)mmalloc(sizeof(char *)*(ac+1));
	for(xp = fp->F_argv ; ac && *av ; av++, xp++, ac--)
		*xp = strsave(*av);
	*xp = 0;
	Cur_ins++;
	Cur_ins->i_buf = savstr;
	Cur_ins->i_ptr = savstr;
	Cur_ins->i_nleft = strlen(savstr);
	Cur_ins->i_fblk = fp;
	in_savblk = 0;
	return(do_end(0, (char **)0)); /* cheat like mad !! */
}

do_while(argc, argv)
char	**argv;
{
	int	ac;
	char	**av, **xp;
	char	*savstr;
	struct	forblk	*fp;

	if(argc < 4)
		syn_err();
	if(strcmp(argv[1], "(") || strcmp(argv[argc-1], ")"))
		syn_err();
	ac = argc - 3;
	av = argv + 2;
	if(Cur_ins >= &in_bufs[MAX_INS]){
		puterr("No resources for while loop.\n");
		return(ERR);
	}
	savstr = read_blk("end", (char *)0);
	if(savstr == NULL)
		return(ERR);
	fp = (struct forblk *)mmalloc(sizeof(struct forblk));
	fp->F_name = 0;
	fp->F_argc = ac;
	fp->F_argv = (char **)mmalloc(sizeof(char *)*(ac+1));
	for(xp = fp->F_argv ; ac && *av ; av++, xp++, ac--)
		*xp = strsave(*av);
	*xp = 0;
	Cur_ins++;
	Cur_ins->i_buf = savstr;
	Cur_ins->i_ptr = savstr;
	Cur_ins->i_nleft = strlen(savstr);
	Cur_ins->i_fblk = fp;
	in_savblk = 0;
	return(do_end(0, (char **)0)); /* cheat like mad !! */
}

char *
read_blk(endstr1, endstr2)
char	*endstr1, *endstr2;
{
	char	*p, *q;
	int	len, olen;

	for(len = 0;;){
		if(Prompt[1])
			put_prompt(Prompt[1]);
		if(readin() == EOF){
			if(in_savblk){
				free(in_savblk);
				in_savblk = 0;
			}
			return(NULL);
		}
		p = skipsp(in_buf);
		if(p != 0)
			olen = strlen(p);
		else
			olen = 0;
		q = mmalloc(len + 1 + olen + 1 + 1);
		if(in_savblk){
			strcpy(q, in_savblk);
			free(in_savblk);
		}
		q[len++] = '\n';
		if(olen)
			strcpy(q + len, p);
		else
			q[len] = 0;
		len += olen;
		in_savblk = q;
		if(olen){
			if(strncmp(p, endstr1, strlen(endstr1)) == 0 ||
			  (endstr2 && strncmp(p, endstr2, strlen(endstr2))==0))
				if(p[olen] == '\0' || index(IFS, p[olen])){	
					strcat(q + olen, "\n");
					break;
				}
		}
	}
	return(in_savblk);
}

do_brk(argc, argv)
char	**argv;
{
	if(Cur_ins->i_fblk == 0){
		puterr("Illegal Break.\n");
		return(ERR);
	}
	return(pop_in(FALSE));
}

do_cont(argc, argv)
char	**argv;
{
	if(Cur_ins->i_fblk == 0){
		puterr("Illegal Continue.\n");
		return(ERR);
	}
	return(do_end(argc, argv));
}

do_end(argc, argv)
char	**argv;
{
	struct	forblk	*fp;
	struct	lvars	*lp;
	char	**xp, **xlp;
	int	res = 0;

	if((fp = Cur_ins->i_fblk) == 0){
		puterr("Illegal end.\n");
		return(ERR);
	}
	if(fp->F_name){
		/* it's a for loop */
		for(lp = Lvars ; lp ; lp = lp->L_next)
			if(strcmp(lp->L_name, fp->F_name) == 0)
				break;
		if(!lp){
			puterr("For: loop variable deleted.\n");
			return(ERR);
		}
		if(xp = lp->L_aval){
			while(*xp)
				free(*xp++);
			free( (char *)lp->L_aval);
		}
		lp->L_aval =(char **)mmalloc(sizeof(char *)*2);
		lp->L_aval[0] = 0;
		lp->L_aval[1] = 0;
		/*
		 * at this point got lp fit to get next val
		 */
		if((xp = fp->F_argv) == 0)
			return(pop_in(FALSE));
		lp->L_aval[0] = *xp;
		while(*xp = xp[1])
			xp++;
		if(fp->F_argv[0] == 0){
			free( (char *)fp->F_argv);
			fp->F_argv = 0;
		}
	}
	else {
		if(arg_eval(fp->F_argc, fp->F_argv, &res) == ERR)
			expr_err();
		if(res == 0)
			return(pop_in(FALSE));
	}
	/*
	 * finally got to the point when we have to restart
	 */
	Cur_ins->i_ptr = Cur_ins->i_buf;
	Cur_ins->i_nleft = strlen(Cur_ins->i_buf);
	return(OK);
}

/*
 * perform an if statement
 */

do_if(argc, argv)
char	**argv;
{
	char	**xp;
	int	ac = 0;
	int	res;
	struct	cmd	T;
	int	level = 0;

	if(argc < 5)
		syn_err();
	if(strcmp(argv[1], "("))
		syn_err();
	for(xp = argv + 2; *xp ; xp++, ac++)
		if(strcmp(*xp, ")") == 0){
			if(--level < 0)
				break;
		}
		else if(strcmp(*xp, "(") == 0)
			level++;
	if(!*xp || !xp[1])
		syn_err();
	if(arg_eval(ac, argv + 2, &res) == ERR)
		expr_err();
	if(strcmp(*++xp, "then") != 0){
		if(!res)
			return(OK);
		/* a simple command - build a tree struct and call r_tree */
		T.cm_parent = 0; T.cm_child = 0; T.cm_next = 0;
		T.cm_ofile = 0; T.cm_ifile = 0;
		T.cm_argv = xp;
		T.cm_argc = argc - ac - 3;
		return(r_tree(&T));
	}
	if(xp[1])
		syn_err();
	/*
	 * Groan - now have to scan to get end of else if construct 
	 */
	return(OK);
}

expr_err()
{
	longjmp(env_main, EXPRERR);
}
