xref: /plan9/sys/src/cmd/sam/cmd.c (revision 82726826a7b3d40fb66339b4b0e95b60314f98b9)
13e12c5d1SDavid du Colombier #include "sam.h"
23e12c5d1SDavid du Colombier #include "parse.h"
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier static char	linex[]="\n";
53e12c5d1SDavid du Colombier static char	wordx[]=" \t\n";
65e91980fSDavid du Colombier Cmdtab cmdtab[]={
73e12c5d1SDavid du Colombier /*	cmdc	text	regexp	addr	defcmd	defaddr	count	token	 fn	*/
83e12c5d1SDavid du Colombier 	'\n',	0,	0,	0,	0,	aDot,	0,	0,	nl_cmd,
93e12c5d1SDavid du Colombier 	'a',	1,	0,	0,	0,	aDot,	0,	0,	a_cmd,
103e12c5d1SDavid du Colombier 	'b',	0,	0,	0,	0,	aNo,	0,	linex,	b_cmd,
113e12c5d1SDavid du Colombier 	'B',	0,	0,	0,	0,	aNo,	0,	linex,	b_cmd,
123e12c5d1SDavid du Colombier 	'c',	1,	0,	0,	0,	aDot,	0,	0,	c_cmd,
133e12c5d1SDavid du Colombier 	'd',	0,	0,	0,	0,	aDot,	0,	0,	d_cmd,
143e12c5d1SDavid du Colombier 	'D',	0,	0,	0,	0,	aNo,	0,	linex,	D_cmd,
153e12c5d1SDavid du Colombier 	'e',	0,	0,	0,	0,	aNo,	0,	wordx,	e_cmd,
163e12c5d1SDavid du Colombier 	'f',	0,	0,	0,	0,	aNo,	0,	wordx,	f_cmd,
173e12c5d1SDavid du Colombier 	'g',	0,	1,	0,	'p',	aDot,	0,	0,	g_cmd,
183e12c5d1SDavid du Colombier 	'i',	1,	0,	0,	0,	aDot,	0,	0,	i_cmd,
193e12c5d1SDavid du Colombier 	'k',	0,	0,	0,	0,	aDot,	0,	0,	k_cmd,
203e12c5d1SDavid du Colombier 	'm',	0,	0,	1,	0,	aDot,	0,	0,	m_cmd,
213e12c5d1SDavid du Colombier 	'n',	0,	0,	0,	0,	aNo,	0,	0,	n_cmd,
223e12c5d1SDavid du Colombier 	'p',	0,	0,	0,	0,	aDot,	0,	0,	p_cmd,
233e12c5d1SDavid du Colombier 	'q',	0,	0,	0,	0,	aNo,	0,	0,	q_cmd,
243e12c5d1SDavid du Colombier 	'r',	0,	0,	0,	0,	aDot,	0,	wordx,	e_cmd,
253e12c5d1SDavid du Colombier 	's',	0,	1,	0,	0,	aDot,	1,	0,	s_cmd,
263e12c5d1SDavid du Colombier 	't',	0,	0,	1,	0,	aDot,	0,	0,	m_cmd,
277dd7cddfSDavid du Colombier 	'u',	0,	0,	0,	0,	aNo,	2,	0,	u_cmd,
283e12c5d1SDavid du Colombier 	'v',	0,	1,	0,	'p',	aDot,	0,	0,	g_cmd,
293e12c5d1SDavid du Colombier 	'w',	0,	0,	0,	0,	aAll,	0,	wordx,	w_cmd,
303e12c5d1SDavid du Colombier 	'x',	0,	1,	0,	'p',	aDot,	0,	0,	x_cmd,
313e12c5d1SDavid du Colombier 	'y',	0,	1,	0,	'p',	aDot,	0,	0,	x_cmd,
323e12c5d1SDavid du Colombier 	'X',	0,	1,	0,	'f',	aNo,	0,	0,	X_cmd,
333e12c5d1SDavid du Colombier 	'Y',	0,	1,	0,	'f',	aNo,	0,	0,	X_cmd,
343e12c5d1SDavid du Colombier 	'!',	0,	0,	0,	0,	aNo,	0,	linex,	plan9_cmd,
353e12c5d1SDavid du Colombier 	'>',	0,	0,	0,	0,	aDot,	0,	linex,	plan9_cmd,
363e12c5d1SDavid du Colombier 	'<',	0,	0,	0,	0,	aDot,	0,	linex,	plan9_cmd,
373e12c5d1SDavid du Colombier 	'|',	0,	0,	0,	0,	aDot,	0,	linex,	plan9_cmd,
383e12c5d1SDavid du Colombier 	'=',	0,	0,	0,	0,	aDot,	0,	linex,	eq_cmd,
393e12c5d1SDavid du Colombier 	'c'|0x100,0,	0,	0,	0,	aNo,	0,	wordx,	cd_cmd,
403e12c5d1SDavid du Colombier 	0,	0,	0,	0,	0,	0,	0,	0,
413e12c5d1SDavid du Colombier };
423e12c5d1SDavid du Colombier Cmd	*parsecmd(int);
433e12c5d1SDavid du Colombier Addr	*compoundaddr(void);
443e12c5d1SDavid du Colombier Addr	*simpleaddr(void);
453e12c5d1SDavid du Colombier void	freecmd(void);
463e12c5d1SDavid du Colombier void	okdelim(int);
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier Rune	line[BLOCKSIZE];
493e12c5d1SDavid du Colombier Rune	termline[BLOCKSIZE];
503e12c5d1SDavid du Colombier Rune	*linep = line;
513e12c5d1SDavid du Colombier Rune	*terminp = termline;
523e12c5d1SDavid du Colombier Rune	*termoutp = termline;
5373e742d7SDavid du Colombier 
5473e742d7SDavid du Colombier List	cmdlist = { 'p' };
5573e742d7SDavid du Colombier List	addrlist = { 'p' };
5673e742d7SDavid du Colombier List	relist = { 'p' };
5773e742d7SDavid du Colombier List	stringlist = { 'p' };
5873e742d7SDavid du Colombier 
593e12c5d1SDavid du Colombier int	eof;
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier void
623e12c5d1SDavid du Colombier resetcmd(void)
633e12c5d1SDavid du Colombier {
643e12c5d1SDavid du Colombier 	linep = line;
653e12c5d1SDavid du Colombier 	*linep = 0;
663e12c5d1SDavid du Colombier 	terminp = termoutp = termline;
673e12c5d1SDavid du Colombier 	freecmd();
683e12c5d1SDavid du Colombier }
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier int
713e12c5d1SDavid du Colombier inputc(void)
723e12c5d1SDavid du Colombier {
733e12c5d1SDavid du Colombier 	int n, nbuf;
74*82726826SDavid du Colombier 	char buf[UTFmax];
753e12c5d1SDavid du Colombier 	Rune r;
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier     Again:
783e12c5d1SDavid du Colombier 	nbuf = 0;
793e12c5d1SDavid du Colombier 	if(downloaded){
803e12c5d1SDavid du Colombier 		while(termoutp == terminp){
813e12c5d1SDavid du Colombier 			cmdupdate();
823e12c5d1SDavid du Colombier 			if(patset)
833e12c5d1SDavid du Colombier 				tellpat();
843e12c5d1SDavid du Colombier 			while(termlocked > 0){
853e12c5d1SDavid du Colombier 				outT0(Hunlock);
863e12c5d1SDavid du Colombier 				termlocked--;
873e12c5d1SDavid du Colombier 			}
883e12c5d1SDavid du Colombier 			if(rcv() == 0)
893e12c5d1SDavid du Colombier 				return -1;
903e12c5d1SDavid du Colombier 		}
913e12c5d1SDavid du Colombier 		r = *termoutp++;
923e12c5d1SDavid du Colombier 		if(termoutp == terminp)
933e12c5d1SDavid du Colombier 			terminp = termoutp = termline;
943e12c5d1SDavid du Colombier 	}else{
953e12c5d1SDavid du Colombier    		do{
963e12c5d1SDavid du Colombier 			n = read(0, buf+nbuf, 1);
973e12c5d1SDavid du Colombier 			if(n <= 0)
983e12c5d1SDavid du Colombier 				return -1;
993e12c5d1SDavid du Colombier 			nbuf += n;
1003e12c5d1SDavid du Colombier 		}while(!fullrune(buf, nbuf));
1013e12c5d1SDavid du Colombier 		chartorune(&r, buf);
1023e12c5d1SDavid du Colombier 	}
1033e12c5d1SDavid du Colombier 	if(r == 0){
1043e12c5d1SDavid du Colombier 		warn(Wnulls);
1053e12c5d1SDavid du Colombier 		goto Again;
1063e12c5d1SDavid du Colombier 	}
1073e12c5d1SDavid du Colombier 	return r;
1083e12c5d1SDavid du Colombier }
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier int
1113e12c5d1SDavid du Colombier inputline(void)
1123e12c5d1SDavid du Colombier {
1135e91980fSDavid du Colombier 	int i, c, start;
1143e12c5d1SDavid du Colombier 
1155e91980fSDavid du Colombier 	/*
1165e91980fSDavid du Colombier 	 * Could set linep = line and i = 0 here and just
1175e91980fSDavid du Colombier 	 * error(Etoolong) below, but this way we keep
1185e91980fSDavid du Colombier 	 * old input buffer history around for a while.
1195e91980fSDavid du Colombier 	 * This is useful only for debugging.
1205e91980fSDavid du Colombier 	 */
1215e91980fSDavid du Colombier 	i = linep - line;
1223e12c5d1SDavid du Colombier 	do{
1233e12c5d1SDavid du Colombier 		if((c = inputc())<=0)
1243e12c5d1SDavid du Colombier 			return -1;
1255e91980fSDavid du Colombier 		if(i == nelem(line)-1){
1265e91980fSDavid du Colombier 			if(linep == line)
1273e12c5d1SDavid du Colombier 				error(Etoolong);
1285e91980fSDavid du Colombier 			start = linep - line;
1295e91980fSDavid du Colombier 			runemove(line, linep, i-start);
1305e91980fSDavid du Colombier 			i -= start;
1315e91980fSDavid du Colombier 			linep = line;
1325e91980fSDavid du Colombier 		}
1333e12c5d1SDavid du Colombier 	}while((line[i++]=c) != '\n');
1343e12c5d1SDavid du Colombier 	line[i] = 0;
1353e12c5d1SDavid du Colombier 	return 1;
1363e12c5d1SDavid du Colombier }
1373e12c5d1SDavid du Colombier 
1383e12c5d1SDavid du Colombier int
1393e12c5d1SDavid du Colombier getch(void)
1403e12c5d1SDavid du Colombier {
1413e12c5d1SDavid du Colombier 	if(eof)
1423e12c5d1SDavid du Colombier 		return -1;
1433e12c5d1SDavid du Colombier 	if(*linep==0 && inputline()<0){
1443e12c5d1SDavid du Colombier 		eof = TRUE;
1453e12c5d1SDavid du Colombier 		return -1;
1463e12c5d1SDavid du Colombier 	}
1473e12c5d1SDavid du Colombier 	return *linep++;
1483e12c5d1SDavid du Colombier }
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier int
1513e12c5d1SDavid du Colombier nextc(void)
1523e12c5d1SDavid du Colombier {
1533e12c5d1SDavid du Colombier 	if(*linep == 0)
1543e12c5d1SDavid du Colombier 		return -1;
1553e12c5d1SDavid du Colombier 	return *linep;
1563e12c5d1SDavid du Colombier }
1573e12c5d1SDavid du Colombier 
1583e12c5d1SDavid du Colombier void
1593e12c5d1SDavid du Colombier ungetch(void)
1603e12c5d1SDavid du Colombier {
1613e12c5d1SDavid du Colombier 	if(--linep < line)
1623e12c5d1SDavid du Colombier 		panic("ungetch");
1633e12c5d1SDavid du Colombier }
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier Posn
1667dd7cddfSDavid du Colombier getnum(int signok)
1673e12c5d1SDavid du Colombier {
1683e12c5d1SDavid du Colombier 	Posn n=0;
1697dd7cddfSDavid du Colombier 	int c, sign;
1703e12c5d1SDavid du Colombier 
1717dd7cddfSDavid du Colombier 	sign = 1;
1727dd7cddfSDavid du Colombier 	if(signok>1 && nextc()=='-'){
1737dd7cddfSDavid du Colombier 		sign = -1;
1747dd7cddfSDavid du Colombier 		getch();
1757dd7cddfSDavid du Colombier 	}
1763e12c5d1SDavid du Colombier 	if((c=nextc())<'0' || '9'<c)	/* no number defaults to 1 */
1777dd7cddfSDavid du Colombier 		return sign;
1783e12c5d1SDavid du Colombier 	while('0'<=(c=getch()) && c<='9')
1793e12c5d1SDavid du Colombier 		n = n*10 + (c-'0');
1803e12c5d1SDavid du Colombier 	ungetch();
1817dd7cddfSDavid du Colombier 	return sign*n;
1823e12c5d1SDavid du Colombier }
1833e12c5d1SDavid du Colombier 
1843e12c5d1SDavid du Colombier int
1853e12c5d1SDavid du Colombier skipbl(void)
1863e12c5d1SDavid du Colombier {
1873e12c5d1SDavid du Colombier 	int c;
1883e12c5d1SDavid du Colombier 	do
1893e12c5d1SDavid du Colombier 		c = getch();
1903e12c5d1SDavid du Colombier 	while(c==' ' || c=='\t');
1913e12c5d1SDavid du Colombier 	if(c >= 0)
1923e12c5d1SDavid du Colombier 		ungetch();
1933e12c5d1SDavid du Colombier 	return c;
1943e12c5d1SDavid du Colombier }
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier void
1973e12c5d1SDavid du Colombier termcommand(void)
1983e12c5d1SDavid du Colombier {
1993e12c5d1SDavid du Colombier 	Posn p;
2003e12c5d1SDavid du Colombier 
2017dd7cddfSDavid du Colombier 	for(p=cmdpt; p<cmd->nc; p++){
2025e91980fSDavid du Colombier 		if(terminp >= termline+nelem(termline)){
2037dd7cddfSDavid du Colombier 			cmdpt = cmd->nc;
2043e12c5d1SDavid du Colombier 			error(Etoolong);
2053e12c5d1SDavid du Colombier 		}
2067dd7cddfSDavid du Colombier 		*terminp++ = filereadc(cmd, p);
2073e12c5d1SDavid du Colombier 	}
2087dd7cddfSDavid du Colombier 	cmdpt = cmd->nc;
2093e12c5d1SDavid du Colombier }
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier void
2123e12c5d1SDavid du Colombier cmdloop(void)
2133e12c5d1SDavid du Colombier {
2143e12c5d1SDavid du Colombier 	Cmd *cmdp;
2153e12c5d1SDavid du Colombier 	File *ocurfile;
2163e12c5d1SDavid du Colombier 	int loaded;
2173e12c5d1SDavid du Colombier 
2183e12c5d1SDavid du Colombier 	for(;;){
2197dd7cddfSDavid du Colombier 		if(!downloaded && curfile && curfile->unread)
2203e12c5d1SDavid du Colombier 			load(curfile);
2213e12c5d1SDavid du Colombier 		if((cmdp = parsecmd(0))==0){
2223e12c5d1SDavid du Colombier 			if(downloaded){
2233e12c5d1SDavid du Colombier 				rescue();
2243e12c5d1SDavid du Colombier 				exits("eof");
2253e12c5d1SDavid du Colombier 			}
2263e12c5d1SDavid du Colombier 			break;
2273e12c5d1SDavid du Colombier 		}
2283e12c5d1SDavid du Colombier 		ocurfile = curfile;
2297dd7cddfSDavid du Colombier 		loaded = curfile && !curfile->unread;
2303e12c5d1SDavid du Colombier 		if(cmdexec(curfile, cmdp) == 0)
2313e12c5d1SDavid du Colombier 			break;
2323e12c5d1SDavid du Colombier 		freecmd();
2333e12c5d1SDavid du Colombier 		cmdupdate();
2343e12c5d1SDavid du Colombier 		update();
2353e12c5d1SDavid du Colombier 		if(downloaded && curfile &&
2367dd7cddfSDavid du Colombier 		    (ocurfile!=curfile || (!loaded && !curfile->unread)))
2373e12c5d1SDavid du Colombier 			outTs(Hcurrent, curfile->tag);
2387dd7cddfSDavid du Colombier 			/* don't allow type ahead on files that aren't bound */
2397dd7cddfSDavid du Colombier 		if(downloaded && curfile && curfile->rasp == 0)
2407dd7cddfSDavid du Colombier 			terminp = termoutp;
2413e12c5d1SDavid du Colombier 	}
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier Cmd *
2453e12c5d1SDavid du Colombier newcmd(void){
2463e12c5d1SDavid du Colombier 	Cmd *p;
2473e12c5d1SDavid du Colombier 
2483e12c5d1SDavid du Colombier 	p = emalloc(sizeof(Cmd));
24973e742d7SDavid du Colombier 	inslist(&cmdlist, cmdlist.nused, p);
2503e12c5d1SDavid du Colombier 	return p;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier Addr*
2543e12c5d1SDavid du Colombier newaddr(void)
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier 	Addr *p;
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier 	p = emalloc(sizeof(Addr));
25973e742d7SDavid du Colombier 	inslist(&addrlist, addrlist.nused, p);
2603e12c5d1SDavid du Colombier 	return p;
2613e12c5d1SDavid du Colombier }
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier String*
2643e12c5d1SDavid du Colombier newre(void)
2653e12c5d1SDavid du Colombier {
2663e12c5d1SDavid du Colombier 	String *p;
2673e12c5d1SDavid du Colombier 
2683e12c5d1SDavid du Colombier 	p = emalloc(sizeof(String));
26973e742d7SDavid du Colombier 	inslist(&relist, relist.nused, p);
2703e12c5d1SDavid du Colombier 	Strinit(p);
2713e12c5d1SDavid du Colombier 	return p;
2723e12c5d1SDavid du Colombier }
2733e12c5d1SDavid du Colombier 
2743e12c5d1SDavid du Colombier String*
2753e12c5d1SDavid du Colombier newstring(void)
2763e12c5d1SDavid du Colombier {
2773e12c5d1SDavid du Colombier 	String *p;
2783e12c5d1SDavid du Colombier 
2793e12c5d1SDavid du Colombier 	p = emalloc(sizeof(String));
28073e742d7SDavid du Colombier 	inslist(&stringlist, stringlist.nused, p);
2813e12c5d1SDavid du Colombier 	Strinit(p);
2823e12c5d1SDavid du Colombier 	return p;
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier 
2853e12c5d1SDavid du Colombier void
2863e12c5d1SDavid du Colombier freecmd(void)
2873e12c5d1SDavid du Colombier {
2883e12c5d1SDavid du Colombier 	int i;
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier 	while(cmdlist.nused > 0)
29173e742d7SDavid du Colombier 		free(cmdlist.voidpptr[--cmdlist.nused]);
2923e12c5d1SDavid du Colombier 	while(addrlist.nused > 0)
29373e742d7SDavid du Colombier 		free(addrlist.voidpptr[--addrlist.nused]);
2943e12c5d1SDavid du Colombier 	while(relist.nused > 0){
2953e12c5d1SDavid du Colombier 		i = --relist.nused;
2963e12c5d1SDavid du Colombier 		Strclose(relist.stringpptr[i]);
2973e12c5d1SDavid du Colombier 		free(relist.stringpptr[i]);
2983e12c5d1SDavid du Colombier 	}
2993e12c5d1SDavid du Colombier 	while(stringlist.nused>0){
3003e12c5d1SDavid du Colombier 		i = --stringlist.nused;
3013e12c5d1SDavid du Colombier 		Strclose(stringlist.stringpptr[i]);
3023e12c5d1SDavid du Colombier 		free(stringlist.stringpptr[i]);
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier int
3073e12c5d1SDavid du Colombier lookup(int c)
3083e12c5d1SDavid du Colombier {
3093e12c5d1SDavid du Colombier 	int i;
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 	for(i=0; cmdtab[i].cmdc; i++)
3123e12c5d1SDavid du Colombier 		if(cmdtab[i].cmdc == c)
3133e12c5d1SDavid du Colombier 			return i;
3143e12c5d1SDavid du Colombier 	return -1;
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier void
3183e12c5d1SDavid du Colombier okdelim(int c)
3193e12c5d1SDavid du Colombier {
3203e12c5d1SDavid du Colombier 	if(c=='\\' || ('a'<=c && c<='z')
3213e12c5d1SDavid du Colombier 	|| ('A'<=c && c<='Z') || ('0'<=c && c<='9'))
3223e12c5d1SDavid du Colombier 		error_c(Edelim, c);
3233e12c5d1SDavid du Colombier }
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier void
3263e12c5d1SDavid du Colombier atnl(void)
3273e12c5d1SDavid du Colombier {
3283e12c5d1SDavid du Colombier 	skipbl();
3293e12c5d1SDavid du Colombier 	if(getch() != '\n')
3303e12c5d1SDavid du Colombier 		error(Enewline);
3313e12c5d1SDavid du Colombier }
3323e12c5d1SDavid du Colombier 
3333e12c5d1SDavid du Colombier void
3343e12c5d1SDavid du Colombier getrhs(String *s, int delim, int cmd)
3353e12c5d1SDavid du Colombier {
3363e12c5d1SDavid du Colombier 	int c;
3373e12c5d1SDavid du Colombier 
3383e12c5d1SDavid du Colombier 	while((c = getch())>0 && c!=delim && c!='\n'){
3393e12c5d1SDavid du Colombier 		if(c == '\\'){
3403e12c5d1SDavid du Colombier 			if((c=getch()) <= 0)
3413e12c5d1SDavid du Colombier 				error(Ebadrhs);
3423e12c5d1SDavid du Colombier 			if(c == '\n'){
3433e12c5d1SDavid du Colombier 				ungetch();
3443e12c5d1SDavid du Colombier 				c='\\';
3453e12c5d1SDavid du Colombier 			}else if(c == 'n')
3463e12c5d1SDavid du Colombier 				c='\n';
3473e12c5d1SDavid du Colombier 			else if(c!=delim && (cmd=='s' || c!='\\'))	/* s does its own */
3483e12c5d1SDavid du Colombier 				Straddc(s, '\\');
3493e12c5d1SDavid du Colombier 		}
3503e12c5d1SDavid du Colombier 		Straddc(s, c);
3513e12c5d1SDavid du Colombier 	}
3523e12c5d1SDavid du Colombier 	ungetch();	/* let client read whether delimeter, '\n' or whatever */
3533e12c5d1SDavid du Colombier }
3543e12c5d1SDavid du Colombier 
3553e12c5d1SDavid du Colombier String *
3563e12c5d1SDavid du Colombier collecttoken(char *end)
3573e12c5d1SDavid du Colombier {
3583e12c5d1SDavid du Colombier 	String *s = newstring();
3593e12c5d1SDavid du Colombier 	int c;
3603e12c5d1SDavid du Colombier 
3613e12c5d1SDavid du Colombier 	while((c=nextc())==' ' || c=='\t')
3623e12c5d1SDavid du Colombier 		Straddc(s, getch()); /* blanks significant for getname() */
3633e12c5d1SDavid du Colombier 	while((c=getch())>0 && utfrune(end, c)==0)
3643e12c5d1SDavid du Colombier 		Straddc(s, c);
3653e12c5d1SDavid du Colombier 	Straddc(s, 0);
3663e12c5d1SDavid du Colombier 	if(c != '\n')
3673e12c5d1SDavid du Colombier 		atnl();
3683e12c5d1SDavid du Colombier 	return s;
3693e12c5d1SDavid du Colombier }
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier String *
3723e12c5d1SDavid du Colombier collecttext(void)
3733e12c5d1SDavid du Colombier {
3743e12c5d1SDavid du Colombier 	String *s = newstring();
3753e12c5d1SDavid du Colombier 	int begline, i, c, delim;
3763e12c5d1SDavid du Colombier 
3773e12c5d1SDavid du Colombier 	if(skipbl()=='\n'){
3783e12c5d1SDavid du Colombier 		getch();
3793e12c5d1SDavid du Colombier 		i = 0;
3803e12c5d1SDavid du Colombier 		do{
3813e12c5d1SDavid du Colombier 			begline = i;
3823e12c5d1SDavid du Colombier 			while((c = getch())>0 && c!='\n')
3833e12c5d1SDavid du Colombier 				i++, Straddc(s, c);
3843e12c5d1SDavid du Colombier 			i++, Straddc(s, '\n');
3853e12c5d1SDavid du Colombier 			if(c < 0)
3863e12c5d1SDavid du Colombier 				goto Return;
3873e12c5d1SDavid du Colombier 		}while(s->s[begline]!='.' || s->s[begline+1]!='\n');
3883e12c5d1SDavid du Colombier 		Strdelete(s, s->n-2, s->n);
3893e12c5d1SDavid du Colombier 	}else{
3903e12c5d1SDavid du Colombier 		okdelim(delim = getch());
3913e12c5d1SDavid du Colombier 		getrhs(s, delim, 'a');
3923e12c5d1SDavid du Colombier 		if(nextc()==delim)
3933e12c5d1SDavid du Colombier 			getch();
3943e12c5d1SDavid du Colombier 		atnl();
3953e12c5d1SDavid du Colombier 	}
3963e12c5d1SDavid du Colombier     Return:
3973e12c5d1SDavid du Colombier 	Straddc(s, 0);		/* JUST FOR CMDPRINT() */
3983e12c5d1SDavid du Colombier 	return s;
3993e12c5d1SDavid du Colombier }
4003e12c5d1SDavid du Colombier 
4013e12c5d1SDavid du Colombier Cmd *
4023e12c5d1SDavid du Colombier parsecmd(int nest)
4033e12c5d1SDavid du Colombier {
4043e12c5d1SDavid du Colombier 	int i, c;
4055e91980fSDavid du Colombier 	Cmdtab *ct;
4063e12c5d1SDavid du Colombier 	Cmd *cp, *ncp;
4073e12c5d1SDavid du Colombier 	Cmd cmd;
4083e12c5d1SDavid du Colombier 
4093e12c5d1SDavid du Colombier 	cmd.next = cmd.ccmd = 0;
4103e12c5d1SDavid du Colombier 	cmd.re = 0;
4113e12c5d1SDavid du Colombier 	cmd.flag = cmd.num = 0;
4123e12c5d1SDavid du Colombier 	cmd.addr = compoundaddr();
4133e12c5d1SDavid du Colombier 	if(skipbl() == -1)
4143e12c5d1SDavid du Colombier 		return 0;
4153e12c5d1SDavid du Colombier 	if((c=getch())==-1)
4163e12c5d1SDavid du Colombier 		return 0;
4173e12c5d1SDavid du Colombier 	cmd.cmdc = c;
4183e12c5d1SDavid du Colombier 	if(cmd.cmdc=='c' && nextc()=='d'){	/* sleazy two-character case */
4193e12c5d1SDavid du Colombier 		getch();		/* the 'd' */
4203e12c5d1SDavid du Colombier 		cmd.cmdc='c'|0x100;
4213e12c5d1SDavid du Colombier 	}
4223e12c5d1SDavid du Colombier 	i = lookup(cmd.cmdc);
4233e12c5d1SDavid du Colombier 	if(i >= 0){
4243e12c5d1SDavid du Colombier 		if(cmd.cmdc == '\n')
4253e12c5d1SDavid du Colombier 			goto Return;	/* let nl_cmd work it all out */
4263e12c5d1SDavid du Colombier 		ct = &cmdtab[i];
4273e12c5d1SDavid du Colombier 		if(ct->defaddr==aNo && cmd.addr)
4283e12c5d1SDavid du Colombier 			error(Enoaddr);
4293e12c5d1SDavid du Colombier 		if(ct->count)
4307dd7cddfSDavid du Colombier 			cmd.num = getnum(ct->count);
4313e12c5d1SDavid du Colombier 		if(ct->regexp){
4323e12c5d1SDavid du Colombier 			/* x without pattern -> .*\n, indicated by cmd.re==0 */
4333e12c5d1SDavid du Colombier 			/* X without pattern is all files */
4343e12c5d1SDavid du Colombier 			if((ct->cmdc!='x' && ct->cmdc!='X') ||
4353e12c5d1SDavid du Colombier 			   ((c = nextc())!=' ' && c!='\t' && c!='\n')){
4363e12c5d1SDavid du Colombier 				skipbl();
4373e12c5d1SDavid du Colombier 				if((c = getch())=='\n' || c<0)
4383e12c5d1SDavid du Colombier 					error(Enopattern);
4393e12c5d1SDavid du Colombier 				okdelim(c);
4403e12c5d1SDavid du Colombier 				cmd.re = getregexp(c);
4413e12c5d1SDavid du Colombier 				if(ct->cmdc == 's'){
4423e12c5d1SDavid du Colombier 					cmd.ctext = newstring();
4433e12c5d1SDavid du Colombier 					getrhs(cmd.ctext, c, 's');
4443e12c5d1SDavid du Colombier 					if(nextc() == c){
4453e12c5d1SDavid du Colombier 						getch();
4463e12c5d1SDavid du Colombier 						if(nextc() == 'g')
4473e12c5d1SDavid du Colombier 							cmd.flag = getch();
4483e12c5d1SDavid du Colombier 					}
4493e12c5d1SDavid du Colombier 
4503e12c5d1SDavid du Colombier 				}
4513e12c5d1SDavid du Colombier 			}
4523e12c5d1SDavid du Colombier 		}
4533e12c5d1SDavid du Colombier 		if(ct->addr && (cmd.caddr=simpleaddr())==0)
4543e12c5d1SDavid du Colombier 			error(Eaddress);
4553e12c5d1SDavid du Colombier 		if(ct->defcmd){
4563e12c5d1SDavid du Colombier 			if(skipbl() == '\n'){
4573e12c5d1SDavid du Colombier 				getch();
4583e12c5d1SDavid du Colombier 				cmd.ccmd = newcmd();
4593e12c5d1SDavid du Colombier 				cmd.ccmd->cmdc = ct->defcmd;
4603e12c5d1SDavid du Colombier 			}else if((cmd.ccmd = parsecmd(nest))==0)
4613e12c5d1SDavid du Colombier 				panic("defcmd");
4623e12c5d1SDavid du Colombier 		}else if(ct->text)
4633e12c5d1SDavid du Colombier 			cmd.ctext = collecttext();
4643e12c5d1SDavid du Colombier 		else if(ct->token)
4653e12c5d1SDavid du Colombier 			cmd.ctext = collecttoken(ct->token);
4663e12c5d1SDavid du Colombier 		else
4673e12c5d1SDavid du Colombier 			atnl();
4683e12c5d1SDavid du Colombier 	}else
4693e12c5d1SDavid du Colombier 		switch(cmd.cmdc){
4703e12c5d1SDavid du Colombier 		case '{':
4713e12c5d1SDavid du Colombier 			cp = 0;
4723e12c5d1SDavid du Colombier 			do{
4733e12c5d1SDavid du Colombier 				if(skipbl()=='\n')
4743e12c5d1SDavid du Colombier 					getch();
4753e12c5d1SDavid du Colombier 				ncp = parsecmd(nest+1);
4763e12c5d1SDavid du Colombier 				if(cp)
4773e12c5d1SDavid du Colombier 					cp->next = ncp;
4783e12c5d1SDavid du Colombier 				else
4793e12c5d1SDavid du Colombier 					cmd.ccmd = ncp;
4803e12c5d1SDavid du Colombier 			}while(cp = ncp);
4813e12c5d1SDavid du Colombier 			break;
4823e12c5d1SDavid du Colombier 		case '}':
4833e12c5d1SDavid du Colombier 			atnl();
4843e12c5d1SDavid du Colombier 			if(nest==0)
4853e12c5d1SDavid du Colombier 				error(Enolbrace);
4863e12c5d1SDavid du Colombier 			return 0;
4873e12c5d1SDavid du Colombier 		default:
4883e12c5d1SDavid du Colombier 			error_c(Eunk, cmd.cmdc);
4893e12c5d1SDavid du Colombier 		}
4903e12c5d1SDavid du Colombier     Return:
4913e12c5d1SDavid du Colombier 	cp = newcmd();
4923e12c5d1SDavid du Colombier 	*cp = cmd;
4933e12c5d1SDavid du Colombier 	return cp;
4943e12c5d1SDavid du Colombier }
4953e12c5d1SDavid du Colombier 
4963e12c5d1SDavid du Colombier String*				/* BUGGERED */
4973e12c5d1SDavid du Colombier getregexp(int delim)
4983e12c5d1SDavid du Colombier {
4993e12c5d1SDavid du Colombier 	String *r = newre();
5003e12c5d1SDavid du Colombier 	int c;
5013e12c5d1SDavid du Colombier 
5023e12c5d1SDavid du Colombier 	for(Strzero(&genstr); ; Straddc(&genstr, c))
5033e12c5d1SDavid du Colombier 		if((c = getch())=='\\'){
5043e12c5d1SDavid du Colombier 			if(nextc()==delim)
5053e12c5d1SDavid du Colombier 				c = getch();
5063e12c5d1SDavid du Colombier 			else if(nextc()=='\\'){
5073e12c5d1SDavid du Colombier 				Straddc(&genstr, c);
5083e12c5d1SDavid du Colombier 				c = getch();
5093e12c5d1SDavid du Colombier 			}
5103e12c5d1SDavid du Colombier 		}else if(c==delim || c=='\n')
5113e12c5d1SDavid du Colombier 			break;
5123e12c5d1SDavid du Colombier 	if(c!=delim && c)
5133e12c5d1SDavid du Colombier 		ungetch();
5143e12c5d1SDavid du Colombier 	if(genstr.n > 0){
5153e12c5d1SDavid du Colombier 		patset = TRUE;
5163e12c5d1SDavid du Colombier 		Strduplstr(&lastpat, &genstr);
5173e12c5d1SDavid du Colombier 		Straddc(&lastpat, '\0');
5183e12c5d1SDavid du Colombier 	}
5193e12c5d1SDavid du Colombier 	if(lastpat.n <= 1)
5203e12c5d1SDavid du Colombier 		error(Epattern);
5213e12c5d1SDavid du Colombier 	Strduplstr(r, &lastpat);
5223e12c5d1SDavid du Colombier 	return r;
5233e12c5d1SDavid du Colombier }
5243e12c5d1SDavid du Colombier 
5253e12c5d1SDavid du Colombier Addr *
5263e12c5d1SDavid du Colombier simpleaddr(void)
5273e12c5d1SDavid du Colombier {
5283e12c5d1SDavid du Colombier 	Addr addr;
5293e12c5d1SDavid du Colombier 	Addr *ap, *nap;
5303e12c5d1SDavid du Colombier 
5313e12c5d1SDavid du Colombier 	addr.next = 0;
5323e12c5d1SDavid du Colombier 	addr.left = 0;
5333e12c5d1SDavid du Colombier 	switch(skipbl()){
5343e12c5d1SDavid du Colombier 	case '#':
5353e12c5d1SDavid du Colombier 		addr.type = getch();
5367dd7cddfSDavid du Colombier 		addr.num = getnum(1);
5373e12c5d1SDavid du Colombier 		break;
5383e12c5d1SDavid du Colombier 	case '0': case '1': case '2': case '3': case '4':
5393e12c5d1SDavid du Colombier 	case '5': case '6': case '7': case '8': case '9':
5407dd7cddfSDavid du Colombier 		addr.num = getnum(1);
5413e12c5d1SDavid du Colombier 		addr.type='l';
5423e12c5d1SDavid du Colombier 		break;
5433e12c5d1SDavid du Colombier 	case '/': case '?': case '"':
5443e12c5d1SDavid du Colombier 		addr.are = getregexp(addr.type = getch());
5453e12c5d1SDavid du Colombier 		break;
5463e12c5d1SDavid du Colombier 	case '.':
5473e12c5d1SDavid du Colombier 	case '$':
5483e12c5d1SDavid du Colombier 	case '+':
5493e12c5d1SDavid du Colombier 	case '-':
5503e12c5d1SDavid du Colombier 	case '\'':
5513e12c5d1SDavid du Colombier 		addr.type = getch();
5523e12c5d1SDavid du Colombier 		break;
5533e12c5d1SDavid du Colombier 	default:
5543e12c5d1SDavid du Colombier 		return 0;
5553e12c5d1SDavid du Colombier 	}
5563e12c5d1SDavid du Colombier 	if(addr.next = simpleaddr())
5573e12c5d1SDavid du Colombier 		switch(addr.next->type){
5583e12c5d1SDavid du Colombier 		case '.':
5593e12c5d1SDavid du Colombier 		case '$':
5603e12c5d1SDavid du Colombier 		case '\'':
5613e12c5d1SDavid du Colombier 			if(addr.type!='"')
5623e12c5d1SDavid du Colombier 		case '"':
5633e12c5d1SDavid du Colombier 				error(Eaddress);
5643e12c5d1SDavid du Colombier 			break;
5653e12c5d1SDavid du Colombier 		case 'l':
5663e12c5d1SDavid du Colombier 		case '#':
5673e12c5d1SDavid du Colombier 			if(addr.type=='"')
5683e12c5d1SDavid du Colombier 				break;
5693e12c5d1SDavid du Colombier 			/* fall through */
5703e12c5d1SDavid du Colombier 		case '/':
5713e12c5d1SDavid du Colombier 		case '?':
5723e12c5d1SDavid du Colombier 			if(addr.type!='+' && addr.type!='-'){
5733e12c5d1SDavid du Colombier 				/* insert the missing '+' */
5743e12c5d1SDavid du Colombier 				nap = newaddr();
5753e12c5d1SDavid du Colombier 				nap->type='+';
5763e12c5d1SDavid du Colombier 				nap->next = addr.next;
5773e12c5d1SDavid du Colombier 				addr.next = nap;
5783e12c5d1SDavid du Colombier 			}
5793e12c5d1SDavid du Colombier 			break;
5803e12c5d1SDavid du Colombier 		case '+':
5813e12c5d1SDavid du Colombier 		case '-':
5823e12c5d1SDavid du Colombier 			break;
5833e12c5d1SDavid du Colombier 		default:
5843e12c5d1SDavid du Colombier 			panic("simpleaddr");
5853e12c5d1SDavid du Colombier 		}
5863e12c5d1SDavid du Colombier 	ap = newaddr();
5873e12c5d1SDavid du Colombier 	*ap = addr;
5883e12c5d1SDavid du Colombier 	return ap;
5893e12c5d1SDavid du Colombier }
5903e12c5d1SDavid du Colombier 
5913e12c5d1SDavid du Colombier Addr *
5923e12c5d1SDavid du Colombier compoundaddr(void)
5933e12c5d1SDavid du Colombier {
5943e12c5d1SDavid du Colombier 	Addr addr;
5953e12c5d1SDavid du Colombier 	Addr *ap, *next;
5963e12c5d1SDavid du Colombier 
5973e12c5d1SDavid du Colombier 	addr.left = simpleaddr();
5983e12c5d1SDavid du Colombier 	if((addr.type = skipbl())!=',' && addr.type!=';')
5993e12c5d1SDavid du Colombier 		return addr.left;
6003e12c5d1SDavid du Colombier 	getch();
6013e12c5d1SDavid du Colombier 	next = addr.next = compoundaddr();
6023e12c5d1SDavid du Colombier 	if(next && (next->type==',' || next->type==';') && next->left==0)
6033e12c5d1SDavid du Colombier 		error(Eaddress);
6043e12c5d1SDavid du Colombier 	ap = newaddr();
6053e12c5d1SDavid du Colombier 	*ap = addr;
6063e12c5d1SDavid du Colombier 	return ap;
6073e12c5d1SDavid du Colombier }
608