/*
 * Csh - a shell by PJAC
 * inp.c input routines
 */
#include "csh.h"

in_1char()
{
	if(Cur_ins->i_nleft <= 0){
		if(Cur_ins->i_fblk){
			puterr("Csh err: End of loop not detected.\n");
			longjmp(env_main, INTERUPT);
		}
		Cur_ins->i_nleft = read(Cur_ins->i_fd,
						Cur_ins->i_buf, MAXINLINE);
		if(Cur_ins->i_nleft <= 0)
			return(EOF);
		Cur_ins->i_ptr = Cur_ins->i_buf;
	}
	Cur_ins->i_nleft--;
	return(*(Cur_ins->i_ptr++) & 0177);
}

readin()
{
	int	c;
	char	*p;
	int	special = FALSE;
	int	mchar = '\0';
	int	mmask = 0;
	int	fchar = TRUE;

	if(in_len > MAXINLINE){
		in_len = MAXINLINE;
		free(in_buf);
		in_buf = mmalloc(MAXINLINE+1);
	}
	for(in_bufp = in_buf; (c = in_1char()) != EOF;){
		switch(c){
		case '\r':
			continue;
		case '\\':
			fchar = FALSE;
			if(special || mchar != '\0')
				goto dflt;
			special = TRUE;
			continue;
		case '\n':
			fchar = FALSE;
			if(special == TRUE){
				special = FALSE;
				add_char(' ' | mmask);
				if(Prompt[1])
					put_prompt(Prompt[1]);
				continue;
			}
			if(mchar != '\0'){
				add_char(c | mmask);
				if(Prompt[1])
					put_prompt(Prompt[1]);
				continue;
			}
			*in_bufp = '\0';
			return(OK);
		case '"':
		case '\'':
			fchar = FALSE;
			if(special)
				goto dflt;
			if(mchar == '\0'){
				add_char(c);
				mchar = c;
				mmask = 0200;
				continue;
			}
			if(mchar != c){
				add_char(c | mmask);
				continue;
			}
			mchar = 0;
			mmask = 0;
			add_char(c);
			continue;
		case '!':
			fchar = FALSE;
			if(special || mchar == '\'')
				goto dflt;
			if(get_hist(mmask) == EOF)
				return(EOF);
			continue;
		case '$':
			fchar = FALSE;
			if(special || mchar == '\'')
				goto dflt;
			if(get_svar(mmask) == EOF)
				return(EOF);
			continue;
		default:
			if(fchar){
				if(c == '^'){
					fchar = FALSE;
					if(get_bhist(mmask) == EOF)
						return(EOF);
					continue;
				}
				else if(index(IFS, c) == 0)
					fchar = FALSE;
			}
		dflt:;
			if(special){
				add_char(c | 0200);
				special = FALSE;
			}
			else
				add_char(c | mmask);
			continue;
		}
	}
	return(EOF);
}

add_char(c)
{
	char	*p;

	if(in_bufp > in_buf + in_len - 1){
		*in_bufp = 0;
		p = mmalloc(in_len + MAXINLINE);
		strcpy(p, in_buf);
		in_bufp = &p[in_bufp - in_buf];
		in_len += MAXINLINE;
		in_buf = p;
	}
	*in_bufp++ = c;
}

/*
 * get a shell variable, copes with $x or ${var} syntax
 */

get_svar(mmask)
{
	char	*p, **xp;
	int	c;
	struct	lvars	*lp;
	int	fmember = -1;
	int	lmember = -1;
	char	*q, *s;
	int	seenb = 0;
	int	fchar = 0;
	int	i;
	char	lbuf[128];
	struct	lvars	*xlp = 0;

	p = lbuf;
	for(p = lbuf ; (c = in_1char()) != EOF; *p++ = c){
		if(c == '{')
			if(p == lbuf)
				continue;
		if(index(IFS, c))
			break;
		if(p > lbuf && *lbuf == '{' && c != '}')
			continue;
		if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			continue;
		if(p == lbuf && (c == '#' || c == '?'))
			continue;
		if(c == '['){
			if(seenb)
				break;
			seenb = 1;
			continue;
		}
		if(c == ']'){
			if(!seenb)
				break;
			if(*lbuf == '{')
				continue;
			*p++ = c;
			c = in_1char();
			break;
		}
		if(c == '-' && seenb)
			continue;
		if(c == '*' || (c >= '0' && c<= '9')){
			if(p == lbuf)
				continue;
			if(p == lbuf + 1){
				if(*lbuf == '{')
					continue;
				if(*lbuf == '?' && c == '0')
					continue;
			}
			if(seenb)
				continue;
		}
		break;
	}
	*p = 0;
	p = lbuf;
	if(*lbuf == '{'){
		if(c != '}'){	/* should be a syntax error */
			Cur_ins->i_nleft++;	/* push back last char */
			Cur_ins->i_ptr--;
			return(ERR);
		}
		p++;
	}
	if(*p == '\0'){
		if(c == EOF)
			return(EOF);
		if(index(IFS, c))
			add_char('$' | mmask);
		if(*lbuf != '{'){
			Cur_ins->i_nleft++;	/* push back last char */
			Cur_ins->i_ptr--;
		}
		return(OK);
	}
	if(c == EOF)
		return(EOF);
		
	if(*lbuf != '{'){
		Cur_ins->i_nleft++;	/* push back last char */
		Cur_ins->i_ptr--;
	}
	q = index(p, '[');
	s = index(p, ']');
	if(s || q){
		if(!q || !s || s < q || *(s+1)) /* error */
			return(ERR);
		*q++ = '\0';
		*s = '\0';
		if(*q == '*'){
			fmember = 1;
			lmember = 10000;	/* a big number */
			q++;
		}
		else {
			if(*q == '-')
				fmember = 1;
			else {
				fmember = 0;
				while(*q >= '0' && *q <= '9')
					fmember = fmember * 10 + (*q++ - '0');
			}
			lmember = fmember;
			if(*q == '-'){
				if(*++q == '\0')
					lmember = 10000;
				else {
					lmember = 0;
					while(*q >= '0' && *q <= '9')
						lmember = lmember * 10 +
								(*q++ - '0');
				}
			}
		}
		if(*q)		/* got a syntax error */
			return(ERR);
		if(lmember < fmember)
			return(OK);
	}
	if(*p == '*'){
		if(fmember != -1)
			return(ERR);
		p = "argv";
		fmember = 1;
		lmember = 10000;
	}
	else if(*p == '0')
		return(ERR); /* don't know name prog was called by */
	else if(*p >= '1' && *p <= '9'){
		if(fmember != -1)
			return(ERR);
		lmember = fmember = atoi(p);
		p = "argv";
	}
	else if(*p == '#' || *p == '?'){
		if(fmember != -1)
			return(ERR);
		if(p[1] == '0' && *p == '?'){
			add_char('0' | mmask); /* we never know the name we */
			return(OK);		/* are called with */
		}
		fchar = *p++;
	}
	if(lmember < 0 && fmember < 0){
		fmember = 1;
		lmember = 10000;
	}
	/*
	 * now find the variable
	 */
	for(lp = Lvars ; lp ; lp = lp->L_next)
		if(strcmp(lp->L_name, p) == 0)
			break;
	if(lp == 0){
		/* maybe the variable is in the environment */
		
		i = strlen(p);
		for(xp = Real_Environ ; *xp ; xp++)
			if(strncmp(*xp, p, i) == 0 && (*xp)[i] == '=')
				break;
		if(*xp){
			/* yep - it's there - build an lvars struct to hold it*/
			xlp = (struct lvars *)mmalloc(sizeof(struct lvars));
			xlp->L_aval = (char **)mmalloc(sizeof(char *) * 2);
			xlp->L_aval[0] = (*xp) + i + 1;
			xlp->L_aval[1] = 0;
			lp = xlp;
		}
	}
	if(lp){
		if(fchar){
			if(fchar == '#'){
				i = 0;
				if(xp = lp->L_aval)
					while(*xp++)
						i++;
				p = my_Itoa(i);
				while(*p)
					add_char(*p++ | mmask);
			}
			else 
				add_char('1' | mmask); /* it exists */
			if(xlp != 0){
				free((char *)xlp->L_aval);
				free((char *)xlp);
			}
			return(OK);
		}
		lmember--;
		fmember--;
		if(xp = lp->L_aval){
			for( ; *xp && fmember > 0 ; xp++, fmember--)
				lmember--;
			while((p = *xp++) && lmember-- >= 0){
				while(*p)
					add_char(*p++ | mmask);
				if(*xp && lmember >= 0)
					add_char(' ' | mmask);
			}
		}
		if(xlp != 0){
			free((char *)xlp->L_aval);
			free((char *)xlp);
		}
	}
	else if(fchar){
		/* string don't exist say so */
		add_char('0' | mmask);
	}
	else if(strcmp(p, "status") == 0){
		p = my_Itoa(status);
		while(*p)
			add_char(*p++ | mmask);
	}
	return(OK);
}
