#include "rc.h"

int	flag[256];
Io	*err;

Channel *wchan;
Thread	*runq;
int	ndot;

void
initpath(void)
{
	char *p;
	char *PATH;
	Word *path, *v;

	if(vlook("path")->val != nil)
		return;
	v = vlook("PATH")->val;
	if(v == nil)
		return;
	PATH = strdup(v->word);
	if(PATH == nil)
		return;
	path = nil;
	while((p = strrchr(PATH, ':')) != nil){
		*p++ = '\0';
		path = newword(p, path);
	}
	path = newword(PATH, path);
	setvar("path", path);
}

void
threadmain(int argc, char *argv[])
{
	int i;
	Code bootstrap[17];
	char *cflag;
	char rcmain[200];
	Var *pmroot;

	cflag = 0;

	/* default to interactive mode */
	flag['i']++;
	
	ARGBEGIN{
	default:
		fprint(2, "usage: %s: [-seiIlvxr] [-c string] [file [args]]\n", argv0);
		threadexitsall("usage");
	case 'D':
		pm_debug = ~0;
		break;
	case 'e': flag['e']++; break;
	case 'c': cflag = ARGF(); break;
	case 'i': flag['i']++; break;
	case 'I': flag['i'] = 0; break;
	case 'l': flag['l']++; break;
	case 'r': flag['r']++; break;
	case 's': flag['s']++; break;
	case 'S': flag['S']++; break;		/* sub shell */
	case 'v': flag['v']++; break;
	case 'V': flag['V']++; break;
	case 'x': flag['x']++; break;
	}ARGEND

	wchan = threadwaitchan();
	err = openfd(2);

	kinit();
	vinit();

	notify(notifyf);

	initpath();

	pmroot = vlook("9pm");
	if(pmroot->val == 0)
		pmroot = vlook("9PM");
	if(pmroot->val == 0)
		pmroot = vlook("ninepm");
	if(pmroot->val == 0)
		pmroot = vlook("NINEPM");
	if(pmroot->val == 0)
		sysfatal("$9pm not set");
	sprint(rcmain, "%s/lib/rcmain", pmroot->val->word);

	setvar("rcname", newword(argv0, 0));
	if(cflag)
		setvar("cflag", newword(cflag, 0));
	else
		setvar("cflag", 0);

	/* bootstrap == . rcmain $* */
	i=0;
	bootstrap[i++].i=1;
	bootstrap[i++].f=Xmark;
	bootstrap[i++].f=Xword;
	bootstrap[i++].s="*";
	bootstrap[i++].f=Xassign;
	bootstrap[i++].f=Xmark;
	bootstrap[i++].f=Xmark;
	bootstrap[i++].f=Xword;
	bootstrap[i++].s="*";
	bootstrap[i++].f=Xdol;
	bootstrap[i++].f=Xword;
	bootstrap[i++].s=rcmain;
	bootstrap[i++].f=Xword;
	bootstrap[i++].s=".";
	bootstrap[i++].f=Xsimple;
	bootstrap[i++].f=Xexit;
	bootstrap[i].i=0;
	start(bootstrap, 1, 0);
	pushlist();
	for(i=argc-1;i>=0;i--)
		pushword(argv[i]);

	for(;;){
		if(flag['r']) pfnc(err, runq);
		runq->pc++;
		(*runq->code[runq->pc-1].f)();
		if(ntrap.ref) {
			dotrap();
		}
	}
}

void
panic(char *s, int n)
{
	pfmt(err, "rcsh: ");
	pfmt(err, s, n);
	pchr(err, '\n');
	flush(err);
	pfmt(err, "aborting\n");
	flush(err);
	threadexitsall("aborting");
}

void
setstatus(char *s)
{
	setvar("status", newword(s, 0));
}

char *
getstatus(void)
{
	Var *status=vlook("status");

	return status->val?status->val->word:"";
}

int
truestatus(void)
{
	char *s;
	for(s=getstatus();*s;s++)
		if(*s!='|' && *s!='0') return 0;
	return 1;
}

char *
concstatus(char *s, char *t)
{
	static char v[NSTATUS+1];
	int n=strlen(s);
	strncpy(v, s, NSTATUS);
	if(n<NSTATUS){
		v[n]='|';
		strncpy(v+n+1, t, NSTATUS-n-1);
	}
	v[NSTATUS]='\0';
	return v;
}

/*
 * Start executing the given code at the given pc with the given redirection
 */
void
start(Code *c, int pc, Var *local)
{
	Thread *p = new(Thread);

	memset(p, 0, sizeof(Thread));
	p->code = codecopy(c);
	p->pc = pc;
	if(runq) {
		p->redir = runq->redir;
		p->startredir = runq->redir;
	}
	p->local = local;
	p->lineno = 1;
	p->ret = runq;
	runq=p;
//fprint(2, "start runq=%p\n", runq);
}

void
execcmds(Io *f)
{
	static Code rdcmds[4];
	static int first=1;

	if(first){
		rdcmds[0].i=1;
		rdcmds[1].f=Xrdcmds;
		rdcmds[2].f=Xreturn;
		first=0;
	}
	start(rdcmds, 1, runq->local);
	runq->cmdfd=f;
	runq->iflast=0;
}

void
waitfor(uint pid)
{
	Thread *p;
	Waitmsg *w;
	char errbuf[ERRMAX];

Again:
	while((w = recvp(wchan)) != nil){
		if(w->pid==pid){
			setstatus(w->msg);
			free(w);
			return;
		}
		for(p=runq->ret;p;p=p->ret)
			if(p->pid==w->pid){
				p->pid=-1;
				strcpy(p->status, w->msg);
			}
		free(w);
	}
	 
	rerrstr(errbuf, sizeof errbuf);
//fprint(2, "wait: err %s\n", errbuf);
	if(strcmp(errbuf, "interrupted")==0)
		goto Again;
}

char **
procargv(char *s0, char *s1, char *s2, char *s3, Word *w)
{
	int n, i;
	Word *p;
	char **argv;

	for(p=w,n=5; p; p=p->next,n++);
		;
	
	argv = malloc(n*sizeof(char*));
	i = 0;
	if(s0)
		argv[i++] = s0;
	if(s1)
		argv[i++] = s1;
	if(s2)
		argv[i++] = s2;
	if(s3)
		argv[i++] = s3;
	for(p=w; p; p=p->next)
		argv[i++] = p->word;
	argv[i] = 0;
	return argv;
}

