#ifdef MSDOS	/* { */
#include	"grep_msd.h"
#endif		/* } */
char sccsID[] = "@(#) csh.c V1.0 Copyright http://www.berklix.com (pjc) 1987\n";
			
/* Csh.c - A shell by PJAC */

#include "csh.h"

/*
 * name of shell used to execute shell scripts
 */

#ifdef	MSDOS
#define	DEF_SHELL	"c:/bin/local/csh.exe"
#else
#define	DEF_SHELL	"/usr/bin/local/csh"
#endif

char	SHELL[MAX_CWD];

char	*in_buf;
char	*in_bufp;
int	in_len;
int	in_ifd;
int	in_ofd;
int	in_efd;
char	*in_savblk;

char	*Args[MAXARGS];
int	Argc = 0;

char	CWD[MAX_CWD];
char	HOME[MAX_CWD];

char	*IFS;

char	*Prompt[2];
char	**Real_Environ;
int	Nenvir;

char	*Path;

char	Special[] = "<>|();&\"'`";

char	IPipe[MAX_CWD];	/* name of pipe file, delete if exists */
char	OPipe[MAX_CWD];

char	*dirstack[MAX_DSTACK];
int	ndirstack;

struct	inbuilt	incmds[] = {
	"cd", do_cd,
	"set", do_set,
	"history", do_hist,
	"alias", do_alias,
	"pwd", do_pwd,
	"unset", do_unset,
	"setenv", do_setenv,
	"unsetenv", do_u_nsetenv,
	"unalias", do_ualias,
#ifdef	MSDOS
	"drive", do_drive,
#endif
	"echo", do_echo,
	"pushd", do_pushd,
	"popd", do_popd,
	"dirs", do_dirs,
	"exit", do_exit,
	"printenv", do_prtenv,
	"rehash", do_rehash,
	"foreach", do_for,
	"shift", do_shift,
	"while", do_while,
	"break", do_brk,
	"continue", do_cont,
	"end", do_end,
	"source", do_source,
	"if", do_if,
	":", do_colon,
	"@", do_atsign,
#ifdef	MSDOS
	"ctty", do_ctty,
#endif
	0, 0,
};

struct	lvars	*Lvars;

/*
 * the list of aliases
 */
struct	lvars	*Aliases;

/*
 * structure to store parse tree state
 */

struct	cmd	*ctree;

char	**History;
int	Curcnum;
int	Hist_siz = -1;
char	*last_cmd;

struct	ins	in_bufs[MAX_INS], *Cur_ins;

jmp_buf	env_main;
int	ctrlcret;

int	status;
int	noglob;
int	igneof;
char	mustcd = FALSE;

/* various flags */
char	cflag, eflag, fflag, iflag, nflag, sflag, tflag;
char	vflag, xflag, XVflag, Pflag;
char	Lflag;	/* flag, set if login shell */
char	sh_script;	/* set if current command is a shell script */
char	in_cshrc;	/* set if reading cshrc */
char	*scr_name;
char	hist_expand;

char	**ARGV ;

main(ac, av)
char	**av;
{
	int	result = 0;
	int	state;
#ifdef	VSL	/* { */
	extern	vsl() ;

	ARGV = av ;
#include	"../../include/vsl.h"
#endif		/* } */

	proc_args(ac, av);
	init(*av);
	bld_hash();	/* build the command hash tables */
	if(!fflag)
		cshrc();
	for(;;){
		re_start();
		if(scr_name && !in_cshrc){
			/* open shell scipt */
			char	*p;
			result = set_input(p = scr_name, FALSE);
			scr_name = 0;
			if(result != OK){
				if(cflag){
					puterr("Can't open '");
					puterr(p);
					puterr("'.\n");
				}
				_exit(ERR);
			}
		}
		state = setjmp(env_main);
		if(state != 0){
			switch(state){
			case INTERUPT:		/* command interupted */
				break;
			case BADPARSE:
				puterr("Syntax error.\n");
				break;
			case NOMEM:
				puterr("No mem.\n");
				break;
			case EXPRERR:
				puterr("Expression error.\n");
				break;
			}
			pop_in(TRUE);
			if(Pflag)
				continue;
			if(eflag || tflag || sh_script)
				_exit(ERR);
			continue;
		}
		if(Prompt[0])
			put_prompt(Prompt[0]);
		hist_expand = FALSE;
		if(readin() == EOF){
			if(pop_in(FALSE) == OK)
				continue;
			if(in_cshrc){
				in_cshrc = FALSE;
				end_cshrc();
				continue;
			}
			if(Pflag || igneof)
				continue;
			_exit(result);
		}
		if(hist_expand){
			put_s(in_buf);
			put_s("\n");
		}
		parse(in_buf, &ctree);
		if(ctree == 0)
			continue;
		if(!in_cshrc && Cur_ins == in_bufs)
			add_to_hist();
		if(vflag && (!in_cshrc || XVflag)){
			put_s(in_buf);
			put_s("\n");
		}
		result = rtree(ctree);
		status = result;
		if(Pflag)
			continue;
		if(eflag && result)
			break;
		if(tflag && !in_cshrc)
			break;
	}
	_exit(result);
}

proc_args(ac, av)
char	**av;
{
	char	*opts;

	if(strcmp(av[0], "-") == 0)
		Lflag = TRUE;
	/* first process args */
	for(ac--, av++ ; *av ; av++, ac--){
		if(*(opts = *av) != '-')
			break;
		for(;*opts ; opts++)
			switch(*opts){
			case 'c':
				cflag = TRUE;
				break;
			case 'e':
				eflag = TRUE;
				break;
			case 'f':
				fflag = TRUE;
				break;
			case 'i':
				iflag = TRUE;
				break;
			case 'n':
				nflag = TRUE;
				break;
			case 's':
				sflag = TRUE;
				break;
			case 't':
				tflag = TRUE;
				break;
			case 'V':
				XVflag = TRUE;
				/* fall through */
			case 'v':
				vflag = TRUE;
				break;
			case 'X':
				XVflag = TRUE;
				/* fall through */
			case 'x':
				xflag = TRUE;
				break;
			case 'P':
				Pflag = TRUE;
				break;
			}
	}
	if(cflag && !ac){
		if(Pflag)
			cflag = 0;
		else
			_exit(1);
	}
	if(ac){	/* got arguments, must be a shell script */
		sh_script = TRUE;
		scr_name = *av;
	}
	if(cflag){
		if(ac > 1)
			set_avs("argv", ac-1, av+1);
	}
	else if(ac)
		set_avs("argv", ac, av);
}

/*
 * start everything off
 */

init(av0)
char	*av0;
{
	char	*getenv();
	char	*p, **xp, **x1p;
	char	*av[2];

	dup2(0, 10);	/* move stdin and stdout, out of the way */
	dup2(1, 11);
	dup2(2, 12);
	in_ifd = 10;
	in_ofd = 11;
	in_efd = 12;
	close(0);
	close(1);
	close(2);
	Cur_ins = in_bufs;
	Cur_ins->i_nleft = 0;
	Cur_ins->i_fd = in_ifd;	/* input is from stdin */
	Cur_ins->i_buf = mmalloc(MAXINLINE+1);	/* allocate an input buffer */
	get_dir();
						/* now get path */
	if( (p = getenv("PATH")) == NULL)
		p = INIT_PATH;
	Path = strsave(p);		/* path components are split by ';' */
	to_fslash(Path);		/* get all strings to be '/'ed */
	to_low(Path);

	if(vflag)
		set_avl("verbose", (char *)0);

	if((p = getenv("SHELL")) == NULL){	/* get the shell var */
#ifdef	MSDOS
		p = av0;
		if(p== 0 || *p == 0)
			p = DEF_SHELL;
#else
		p = DEF_SHELL;
#endif
	}
	set_avl("shell", p);

	set_avl("prompt", INIT_PROMPT);		/* set up prompts */
	Prompt[1] = strsave(INIT_SPROMPT);	/* set up prompts */

	if((p = getenv("HOME")) == NULL)	/* set up home directory */
		p = CWD;
	set_avl("home", p);

	if(xflag)
		set_avl("echo", (char *)0);

	if((p = getenv("IFS")) == NULL)		/* get IFS string */
		p = INIT_IFS;
	IFS = strsave(p);

	in_buf = mmalloc(MAXINLINE+1);
	in_len = MAXINLINE;
	Curcnum = 1;
	/*
	 * set up environment
	 */
	for(xp = environ ; *xp ; xp++, Nenvir++);
	Real_Environ = (char **)mmalloc(sizeof(char *)*(Nenvir+1));
	for(x1p = Real_Environ, xp = environ ; (*x1p++ = *xp++););
}

/*
 * reinitialise all variables
 */

re_start()
{
	int	ctrlctrap();

	dup2(in_ifd, 0);
	dup2(in_ofd, 1);
	dup2(in_efd, 2);
	if(mustcd){
		mustcd = FALSE;
#ifdef	MSDOS
		if(chdir(CWD) < 0){
			puterr("Cannot CHDIR back - CWD is now ");
			get_dir();
			puterr(CWD);
			puterr("\n");
		}
#endif
	}
	if(ctree){	/* junk last command tree */
		free_tree(ctree);
		ctree = 0;
		if(*IPipe){	/* close and junk any pipes */
			unlink(IPipe);
			*IPipe = 0;
		}
		if(*OPipe){	/* close and junk any pipes */
			unlink(OPipe);
			*OPipe = 0;
		}
	}
	if(in_savblk){
		free(in_savblk);
		in_savblk = 0;
	}
	signal(SIGINT, ctrlctrap);
	ctrlcret = INTERUPT;
}

ctrlctrap()
{
	signal(SIGINT, SIG_IGN);
	longjmp(env_main, ctrlcret);
}

/*
 * Try to execute the cshrc file
 */

static	int	cshrc_fd;

cshrc()
{
	char	lbuf[128];

	strcpy(lbuf, HOME);
	strcat(lbuf, "/cshrc");
	cshrc_fd = Cur_ins->i_fd;
	re_start();	/* get the fd's back */
	if(set_input(lbuf, FALSE) == OK)
		in_cshrc = TRUE;
}

/*
 * source a file
 */

do_source(argc, argv)
char	**argv;
{
	if(argc < 2)
		syn_err();
	return(set_input(argv[1], TRUE));
}

/*
 * set input to be file - used by shell scripts and cshrc and sourceing
 */

set_input(file, is_source)
char	*file;
{
	int	fd;

	if(!is_source && Cur_ins != in_bufs)
		return(ERR);
	if(is_source && Cur_ins >= &in_bufs[MAX_INS]){
		puterr("No resources for source.\n");
		return(ERR);
	}
	fd = open(file, 0);
	if(fd < 0){
		if(is_source)
			puterr("Can't open source file.\n");
		return(ERR);
	}
	if(is_source){
		Cur_ins++;
		Cur_ins->i_buf = mmalloc(MAXINLINE+1);	/* allocate buffer */
	}
	Cur_ins->i_nleft = 0;
	Cur_ins->i_fd = fd;
	return(OK);
}

end_cshrc()
{
	close(Cur_ins->i_fd);
	Cur_ins->i_fd = cshrc_fd;
}

/*
 * pop the input source stack
 */
pop_in(unstack)
{
	struct	forblk	*fp;
	char	**xp;

	if(Cur_ins < &in_bufs[1])
		return(ERR);
	while(Cur_ins >= &in_bufs[1]){
		if(fp = Cur_ins->i_fblk){
			if(fp->F_name)
				free(fp->F_name);
			if(xp = fp->F_argv){
				while(*xp)
					free(*xp++);
				free( (char *)fp->F_argv);
			}
			free( (char *)fp);
			Cur_ins->i_fblk = 0;
		}
		else
			close(Cur_ins->i_fd);
		free(Cur_ins->i_buf);
		Cur_ins--;
		if(!unstack)
			break;
	}
	return(OK);
}
