xref: /plan9/sys/src/cmd/plumb/rules.c (revision 9b7bf7df4595c26f1e9b67beb0c6e44c9876fb05)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <regexp.h>
57dd7cddfSDavid du Colombier #include <thread.h>
67dd7cddfSDavid du Colombier #include <ctype.h>
77dd7cddfSDavid du Colombier #include <plumb.h>
87dd7cddfSDavid du Colombier #include "plumber.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier typedef struct Input Input;
117dd7cddfSDavid du Colombier typedef struct Var Var;
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier struct Input
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier 	char		*file;		/* name of file */
167dd7cddfSDavid du Colombier 	Biobuf	*fd;		/* input buffer, if from real file */
177dd7cddfSDavid du Colombier 	uchar	*s;		/* input string, if from /mnt/plumb/rules */
187dd7cddfSDavid du Colombier 	uchar	*end;	/* end of input string */
197dd7cddfSDavid du Colombier 	int		lineno;
207dd7cddfSDavid du Colombier 	Input	*next;	/* file to read after EOF on this one */
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier struct Var
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier 	char	*name;
267dd7cddfSDavid du Colombier 	char	*value;
277dd7cddfSDavid du Colombier 	char *qvalue;
287dd7cddfSDavid du Colombier };
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier static int		parsing;
317dd7cddfSDavid du Colombier static int		nvars;
327dd7cddfSDavid du Colombier static Var		*vars;
337dd7cddfSDavid du Colombier static Input	*input;
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier static char 	ebuf[4096];
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier char *badports[] =
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier 	".",
407dd7cddfSDavid du Colombier 	"..",
417dd7cddfSDavid du Colombier 	"send",
427dd7cddfSDavid du Colombier 	nil
437dd7cddfSDavid du Colombier };
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier char *objects[] =
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier 	"arg",
487dd7cddfSDavid du Colombier 	"attr",
497dd7cddfSDavid du Colombier 	"data",
507dd7cddfSDavid du Colombier 	"dst",
517dd7cddfSDavid du Colombier 	"plumb",
527dd7cddfSDavid du Colombier 	"src",
537dd7cddfSDavid du Colombier 	"type",
5459cc4ca5SDavid du Colombier 	"wdir",
557dd7cddfSDavid du Colombier 	nil
567dd7cddfSDavid du Colombier };
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier char *verbs[] =
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier 	"add",
617dd7cddfSDavid du Colombier 	"client",
627dd7cddfSDavid du Colombier 	"delete",
637dd7cddfSDavid du Colombier 	"is",
647dd7cddfSDavid du Colombier 	"isdir",
657dd7cddfSDavid du Colombier 	"isfile",
667dd7cddfSDavid du Colombier 	"matches",
677dd7cddfSDavid du Colombier 	"set",
687dd7cddfSDavid du Colombier 	"start",
697dd7cddfSDavid du Colombier 	"to",
707dd7cddfSDavid du Colombier 	nil
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier static void
printinputstackrev(Input * in)747dd7cddfSDavid du Colombier printinputstackrev(Input *in)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	if(in == nil)
777dd7cddfSDavid du Colombier 		return;
787dd7cddfSDavid du Colombier 	printinputstackrev(in->next);
799a747e4fSDavid du Colombier 	fprint(2, "%s:%d: ", in->file, in->lineno);
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier void
printinputstack(void)837dd7cddfSDavid du Colombier printinputstack(void)
847dd7cddfSDavid du Colombier {
857dd7cddfSDavid du Colombier 	printinputstackrev(input);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier static void
pushinput(char * name,int fd,uchar * str)897dd7cddfSDavid du Colombier pushinput(char *name, int fd, uchar *str)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	Input *in;
927dd7cddfSDavid du Colombier 	int depth;
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	depth = 0;
957dd7cddfSDavid du Colombier 	for(in=input; in; in=in->next)
967dd7cddfSDavid du Colombier 		if(depth++ >= 10)	/* prevent deep C stack in plumber and bad include structure */
977dd7cddfSDavid du Colombier 			parseerror("include stack too deep; max 10");
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier 	in = emalloc(sizeof(Input));
1007dd7cddfSDavid du Colombier 	in->file = estrdup(name);
1017dd7cddfSDavid du Colombier 	in->next = input;
1027dd7cddfSDavid du Colombier 	input = in;
1037dd7cddfSDavid du Colombier 	if(str)
1047dd7cddfSDavid du Colombier 		in->s = str;
1057dd7cddfSDavid du Colombier 	else{
1067dd7cddfSDavid du Colombier 		in->fd = emalloc(sizeof(Biobuf));
1077dd7cddfSDavid du Colombier 		if(Binit(in->fd, fd, OREAD) < 0)
1087dd7cddfSDavid du Colombier 			parseerror("can't initialize Bio for rules file: %r");
1097dd7cddfSDavid du Colombier 	}
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier int
popinput(void)1147dd7cddfSDavid du Colombier popinput(void)
1157dd7cddfSDavid du Colombier {
1167dd7cddfSDavid du Colombier 	Input *in;
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	in = input;
1197dd7cddfSDavid du Colombier 	if(in == nil)
1207dd7cddfSDavid du Colombier 		return 0;
1217dd7cddfSDavid du Colombier 	input = in->next;
1227dd7cddfSDavid du Colombier 	if(in->fd){
1237dd7cddfSDavid du Colombier 		Bterm(in->fd);
1247dd7cddfSDavid du Colombier 		free(in->fd);
1257dd7cddfSDavid du Colombier 	}
126*9b7bf7dfSDavid du Colombier 	free(in->file);
1277dd7cddfSDavid du Colombier 	free(in);
1287dd7cddfSDavid du Colombier 	return 1;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier int
getc(void)1327dd7cddfSDavid du Colombier getc(void)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier 	if(input == nil)
1357dd7cddfSDavid du Colombier 		return Beof;
1367dd7cddfSDavid du Colombier 	if(input->fd)
1377dd7cddfSDavid du Colombier 		return Bgetc(input->fd);
1387dd7cddfSDavid du Colombier 	if(input->s < input->end)
1397dd7cddfSDavid du Colombier 		return *(input->s)++;
1407dd7cddfSDavid du Colombier 	return -1;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier char*
getline(void)1447dd7cddfSDavid du Colombier getline(void)
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier 	static int n = 0;
1477dd7cddfSDavid du Colombier 	static char *s, *incl;
1487dd7cddfSDavid du Colombier 	int c, i;
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier 	i = 0;
1517dd7cddfSDavid du Colombier 	for(;;){
1527dd7cddfSDavid du Colombier 		c = getc();
1537dd7cddfSDavid du Colombier 		if(c < 0)
1547dd7cddfSDavid du Colombier 			return nil;
1557dd7cddfSDavid du Colombier 		if(i == n){
1567dd7cddfSDavid du Colombier 			n += 100;
1577dd7cddfSDavid du Colombier 			s = erealloc(s, n);
1587dd7cddfSDavid du Colombier 		}
1597dd7cddfSDavid du Colombier 		if(c<0 || c=='\0' || c=='\n')
1607dd7cddfSDavid du Colombier 			break;
1617dd7cddfSDavid du Colombier 		s[i++] = c;
1627dd7cddfSDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	s[i] = '\0';
1647dd7cddfSDavid du Colombier 	return s;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier int
lookup(char * s,char * tab[])1687dd7cddfSDavid du Colombier lookup(char *s, char *tab[])
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	int i;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	for(i=0; tab[i]!=nil; i++)
1737dd7cddfSDavid du Colombier 		if(strcmp(s, tab[i])==0)
1747dd7cddfSDavid du Colombier 			return i;
1757dd7cddfSDavid du Colombier 	return -1;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier Var*
lookupvariable(char * s,int n)1797dd7cddfSDavid du Colombier lookupvariable(char *s, int n)
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier 	int i;
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	for(i=0; i<nvars; i++)
1847dd7cddfSDavid du Colombier 		if(n==strlen(vars[i].name) && memcmp(s, vars[i].name, n)==0)
1857dd7cddfSDavid du Colombier 			return vars+i;
1867dd7cddfSDavid du Colombier 	return nil;
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier char*
variable(char * s,int n)1907dd7cddfSDavid du Colombier variable(char *s, int n)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier 	Var *var;
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	var = lookupvariable(s, n);
1957dd7cddfSDavid du Colombier 	if(var)
1967dd7cddfSDavid du Colombier 		return var->qvalue;
1977dd7cddfSDavid du Colombier 	return nil;
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier void
setvariable(char * s,int n,char * val,char * qval)2017dd7cddfSDavid du Colombier setvariable(char  *s, int n, char *val, char *qval)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier 	Var *var;
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	var = lookupvariable(s, n);
2067dd7cddfSDavid du Colombier 	if(var){
2077dd7cddfSDavid du Colombier 		free(var->value);
2087dd7cddfSDavid du Colombier 		free(var->qvalue);
2097dd7cddfSDavid du Colombier 	}else{
2107dd7cddfSDavid du Colombier 		vars = erealloc(vars, (nvars+1)*sizeof(Var));
2117dd7cddfSDavid du Colombier 		var = vars+nvars++;
2127dd7cddfSDavid du Colombier 		var->name = emalloc(n+1);
2137dd7cddfSDavid du Colombier 		memmove(var->name, s, n);
2147dd7cddfSDavid du Colombier 	}
2157dd7cddfSDavid du Colombier 	var->value = estrdup(val);
2167dd7cddfSDavid du Colombier 	var->qvalue = estrdup(qval);
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier static char*
nonnil(char * s)2207dd7cddfSDavid du Colombier nonnil(char *s)
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier 	if(s == nil)
2237dd7cddfSDavid du Colombier 		return "";
2247dd7cddfSDavid du Colombier 	return s;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier static char*
filename(Exec * e,char * name)2287dd7cddfSDavid du Colombier filename(Exec *e, char *name)
2297dd7cddfSDavid du Colombier {
2307dd7cddfSDavid du Colombier 	static char *buf;	/* rock to hold value so we don't leak the strings */
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 	free(buf);
2337dd7cddfSDavid du Colombier 	/* if name is defined, used it */
2347dd7cddfSDavid du Colombier 	if(name!=nil && name[0]!='\0'){
2357dd7cddfSDavid du Colombier 		buf = estrdup(name);
2367dd7cddfSDavid du Colombier 		return cleanname(buf);
2377dd7cddfSDavid du Colombier 	}
2387dd7cddfSDavid du Colombier 	/* if data is an absolute file name, or wdir is empty, use it */
2397dd7cddfSDavid du Colombier 	if(e->msg->data[0]=='/' || e->msg->wdir==nil || e->msg->wdir[0]=='\0'){
2407dd7cddfSDavid du Colombier 		buf = estrdup(e->msg->data);
2417dd7cddfSDavid du Colombier 		return cleanname(buf);
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier 	buf = emalloc(strlen(e->msg->wdir)+1+strlen(e->msg->data)+1);
2447dd7cddfSDavid du Colombier 	sprint(buf, "%s/%s", e->msg->wdir, e->msg->data);
2457dd7cddfSDavid du Colombier 	return cleanname(buf);
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier 
2487dd7cddfSDavid du Colombier char*
dollar(Exec * e,char * s,int * namelen)2497dd7cddfSDavid du Colombier dollar(Exec *e, char *s, int *namelen)
2507dd7cddfSDavid du Colombier {
2517dd7cddfSDavid du Colombier 	int n;
2527dd7cddfSDavid du Colombier 	static char *abuf;
2537dd7cddfSDavid du Colombier 	char *t;
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	*namelen = 1;
2567dd7cddfSDavid du Colombier 	if(e!=nil && '0'<=s[0] && s[0]<='9')
2577dd7cddfSDavid du Colombier 		return nonnil(e->match[s[0]-'0']);
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier 	for(t=s; isalnum(*t); t++)
2607dd7cddfSDavid du Colombier 		;
2617dd7cddfSDavid du Colombier 	n = t-s;
2627dd7cddfSDavid du Colombier 	*namelen = n;
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier 	if(e != nil){
2657dd7cddfSDavid du Colombier 		if(n == 3){
2667dd7cddfSDavid du Colombier 			if(memcmp(s, "src", 3) == 0)
2677dd7cddfSDavid du Colombier 				return nonnil(e->msg->src);
2687dd7cddfSDavid du Colombier 			if(memcmp(s, "dst", 3) == 0)
2697dd7cddfSDavid du Colombier 				return nonnil(e->msg->dst);
2707dd7cddfSDavid du Colombier 			if(memcmp(s, "dir", 3) == 0)
2717dd7cddfSDavid du Colombier 				return filename(e, e->dir);
2727dd7cddfSDavid du Colombier 		}
2737dd7cddfSDavid du Colombier 		if(n == 4){
2747dd7cddfSDavid du Colombier 			if(memcmp(s, "attr", 4) == 0){
2757dd7cddfSDavid du Colombier 				free(abuf);
2767dd7cddfSDavid du Colombier 				abuf = plumbpackattr(e->msg->attr);
2777dd7cddfSDavid du Colombier 				return nonnil(abuf);
2787dd7cddfSDavid du Colombier 			}
2797dd7cddfSDavid du Colombier 			if(memcmp(s, "data", 4) == 0)
2807dd7cddfSDavid du Colombier 				return nonnil(e->msg->data);
2817dd7cddfSDavid du Colombier 			if(memcmp(s, "file", 4) == 0)
2827dd7cddfSDavid du Colombier 				return filename(e, e->file);
2837dd7cddfSDavid du Colombier 			if(memcmp(s, "type", 4) == 0)
2847dd7cddfSDavid du Colombier 				return nonnil(e->msg->type);
2857dd7cddfSDavid du Colombier 			if(memcmp(s, "wdir", 3) == 0)
2867dd7cddfSDavid du Colombier 				return nonnil(e->msg->wdir);
2877dd7cddfSDavid du Colombier 		}
2887dd7cddfSDavid du Colombier 	}
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	return variable(s, n);
2917dd7cddfSDavid du Colombier }
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier /* expand one blank-terminated string, processing quotes and $ signs */
2947dd7cddfSDavid du Colombier char*
expand(Exec * e,char * s,char ** ends)2957dd7cddfSDavid du Colombier expand(Exec *e, char *s, char **ends)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	char *p, *ep, *val;
2987dd7cddfSDavid du Colombier 	int namelen, quoting;
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	p = ebuf;
3017dd7cddfSDavid du Colombier 	ep = ebuf+sizeof ebuf-1;
3027dd7cddfSDavid du Colombier 	quoting = 0;
3037dd7cddfSDavid du Colombier 	while(p<ep && *s!='\0' && (quoting || (*s!=' ' && *s!='\t'))){
3047dd7cddfSDavid du Colombier 		if(*s == '\''){
3057dd7cddfSDavid du Colombier 			s++;
3067dd7cddfSDavid du Colombier 			if(!quoting)
3077dd7cddfSDavid du Colombier 				quoting = 1;
3087dd7cddfSDavid du Colombier 			else  if(*s == '\''){
3097dd7cddfSDavid du Colombier 				*p++ = '\'';
3107dd7cddfSDavid du Colombier 				s++;
3117dd7cddfSDavid du Colombier 			}else
3127dd7cddfSDavid du Colombier 				quoting = 0;
3137dd7cddfSDavid du Colombier 			continue;
3147dd7cddfSDavid du Colombier 		}
3157dd7cddfSDavid du Colombier 		if(quoting || *s!='$'){
3167dd7cddfSDavid du Colombier 			*p++ = *s++;
3177dd7cddfSDavid du Colombier 			continue;
3187dd7cddfSDavid du Colombier 		}
3197dd7cddfSDavid du Colombier 		s++;
3207dd7cddfSDavid du Colombier 		val = dollar(e, s, &namelen);
3217dd7cddfSDavid du Colombier 		if(val == nil){
3227dd7cddfSDavid du Colombier 			*p++ = '$';
3237dd7cddfSDavid du Colombier 			continue;
3247dd7cddfSDavid du Colombier 		}
3257dd7cddfSDavid du Colombier 		if(ep-p < strlen(val))
3267dd7cddfSDavid du Colombier 			return "string-too-long";
3277dd7cddfSDavid du Colombier 		strcpy(p, val);
3287dd7cddfSDavid du Colombier 		p += strlen(val);
3297dd7cddfSDavid du Colombier 		s += namelen;
3307dd7cddfSDavid du Colombier 	}
3317dd7cddfSDavid du Colombier 	if(ends)
3327dd7cddfSDavid du Colombier 		*ends = s;
3337dd7cddfSDavid du Colombier 	*p = '\0';
3347dd7cddfSDavid du Colombier 	return ebuf;
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier void
regerror(char * msg)3387dd7cddfSDavid du Colombier regerror(char *msg)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier 	if(parsing){
3417dd7cddfSDavid du Colombier 		parsing = 0;
3427dd7cddfSDavid du Colombier 		parseerror("%s", msg);
3437dd7cddfSDavid du Colombier 	}
3447dd7cddfSDavid du Colombier 	error("%s", msg);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier void
parserule(Rule * r)3487dd7cddfSDavid du Colombier parserule(Rule *r)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier 	r->qarg = estrdup(expand(nil, r->arg, nil));
3517dd7cddfSDavid du Colombier 	switch(r->obj){
3527dd7cddfSDavid du Colombier 	case OArg:
3537dd7cddfSDavid du Colombier 	case OAttr:
3547dd7cddfSDavid du Colombier 	case OData:
3557dd7cddfSDavid du Colombier 	case ODst:
3567dd7cddfSDavid du Colombier 	case OType:
35759cc4ca5SDavid du Colombier 	case OWdir:
3587dd7cddfSDavid du Colombier 	case OSrc:
3597dd7cddfSDavid du Colombier 		if(r->verb==VClient || r->verb==VStart || r->verb==VTo)
3607dd7cddfSDavid du Colombier 			parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3617dd7cddfSDavid du Colombier 		if(r->obj!=OAttr && (r->verb==VAdd || r->verb==VDelete))
3627dd7cddfSDavid du Colombier 			parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3637dd7cddfSDavid du Colombier 		if(r->verb == VMatches){
3647dd7cddfSDavid du Colombier 			r->regex = regcomp(r->qarg);
3657dd7cddfSDavid du Colombier 			return;
3667dd7cddfSDavid du Colombier 		}
3677dd7cddfSDavid du Colombier 		break;
3687dd7cddfSDavid du Colombier 	case OPlumb:
3697dd7cddfSDavid du Colombier 		if(r->verb!=VClient && r->verb!=VStart && r->verb!=VTo)
3707dd7cddfSDavid du Colombier 			parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3717dd7cddfSDavid du Colombier 		break;
3727dd7cddfSDavid du Colombier 	}
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier int
assignment(char * p)3767dd7cddfSDavid du Colombier assignment(char *p)
3777dd7cddfSDavid du Colombier {
3787dd7cddfSDavid du Colombier 	char *var, *qval;
3797dd7cddfSDavid du Colombier 	int n;
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier 	if(!isalpha(p[0]))
3827dd7cddfSDavid du Colombier 		return 0;
3837dd7cddfSDavid du Colombier 	for(var=p; isalnum(*p); p++)
3847dd7cddfSDavid du Colombier 		;
3857dd7cddfSDavid du Colombier 	n = p-var;
3867dd7cddfSDavid du Colombier 	while(*p==' ' || *p=='\t')
3877dd7cddfSDavid du Colombier 			p++;
3887dd7cddfSDavid du Colombier 	if(*p++ != '=')
3897dd7cddfSDavid du Colombier 		return 0;
3907dd7cddfSDavid du Colombier 	while(*p==' ' || *p=='\t')
3917dd7cddfSDavid du Colombier 			p++;
3927dd7cddfSDavid du Colombier 	qval = expand(nil, p, nil);
3937dd7cddfSDavid du Colombier 	setvariable(var, n, p, qval);
3947dd7cddfSDavid du Colombier 	return 1;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier int
include(char * s)3987dd7cddfSDavid du Colombier include(char *s)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier 	char *t, *args[3], buf[128];
4017dd7cddfSDavid du Colombier 	int n, fd;
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier 	if(strncmp(s, "include", 7) != 0)
4047dd7cddfSDavid du Colombier 		return 0;
4057dd7cddfSDavid du Colombier 	/* either an include or an error */
4067dd7cddfSDavid du Colombier 	n = tokenize(s, args, nelem(args));
4077dd7cddfSDavid du Colombier 	if(n < 2)
4087dd7cddfSDavid du Colombier 		goto Err;
4097dd7cddfSDavid du Colombier 	if(strcmp(args[0], "include") != 0)
4107dd7cddfSDavid du Colombier 		goto Err;
4117dd7cddfSDavid du Colombier 	if(args[1][0] == '#')
4127dd7cddfSDavid du Colombier 		goto Err;
4137dd7cddfSDavid du Colombier 	if(n>2 && args[2][0] != '#')
4147dd7cddfSDavid du Colombier 		goto Err;
4157dd7cddfSDavid du Colombier 	t = args[1];
4167dd7cddfSDavid du Colombier 	fd = open(t, OREAD);
4177dd7cddfSDavid du Colombier 	if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
4187dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf, "/sys/lib/plumb/%s", t);
4197dd7cddfSDavid du Colombier 		t = buf;
4207dd7cddfSDavid du Colombier 		fd = open(t, OREAD);
4217dd7cddfSDavid du Colombier 	}
4227dd7cddfSDavid du Colombier 	if(fd < 0)
4237dd7cddfSDavid du Colombier 		parseerror("can't open %s for inclusion", t);
4247dd7cddfSDavid du Colombier 	pushinput(t, fd, nil);
4257dd7cddfSDavid du Colombier 	return 1;
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier     Err:
4287dd7cddfSDavid du Colombier 	parseerror("malformed include statement");
4297dd7cddfSDavid du Colombier 	return 0;
4307dd7cddfSDavid du Colombier }
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier Rule*
readrule(int * eof)4337dd7cddfSDavid du Colombier readrule(int *eof)
4347dd7cddfSDavid du Colombier {
4357dd7cddfSDavid du Colombier 	Rule *rp;
4367dd7cddfSDavid du Colombier 	char *line, *p;
4377dd7cddfSDavid du Colombier 	char *word;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier Top:
4407dd7cddfSDavid du Colombier 	line = getline();
4417dd7cddfSDavid du Colombier 	if(line == nil){
4427dd7cddfSDavid du Colombier 		/*
4437dd7cddfSDavid du Colombier 		 * if input is from string, and bytes remain (input->end is within string),
4447dd7cddfSDavid du Colombier 		 * morerules() will pop input and save remaining data.  otherwise pop
4457dd7cddfSDavid du Colombier 		 * the stack here, and if there's more input, keep reading.
4467dd7cddfSDavid du Colombier 		 */
4477dd7cddfSDavid du Colombier 		if((input!=nil && input->end==nil) && popinput())
4487dd7cddfSDavid du Colombier 			goto Top;
4497dd7cddfSDavid du Colombier 		*eof = 1;
4507dd7cddfSDavid du Colombier 		return nil;
4517dd7cddfSDavid du Colombier 	}
4527dd7cddfSDavid du Colombier 	input->lineno++;
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier 	for(p=line; *p==' ' || *p=='\t'; p++)
4557dd7cddfSDavid du Colombier 		;
4567dd7cddfSDavid du Colombier 	if(*p=='\0' || *p=='#')	/* empty or comment line */
4577dd7cddfSDavid du Colombier 		return nil;
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	if(include(p))
4607dd7cddfSDavid du Colombier 		goto Top;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	if(assignment(p))
4637dd7cddfSDavid du Colombier 		return nil;
4647dd7cddfSDavid du Colombier 
4657dd7cddfSDavid du Colombier 	rp = emalloc(sizeof(Rule));
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	/* object */
4687dd7cddfSDavid du Colombier 	for(word=p; *p!=' ' && *p!='\t'; p++)
4697dd7cddfSDavid du Colombier 		if(*p == '\0')
4707dd7cddfSDavid du Colombier 			parseerror("malformed rule");
4717dd7cddfSDavid du Colombier 	*p++ = '\0';
4727dd7cddfSDavid du Colombier 	rp->obj = lookup(word, objects);
4737dd7cddfSDavid du Colombier 	if(rp->obj < 0){
4747dd7cddfSDavid du Colombier 		if(strcmp(word, "kind") == 0)	/* backwards compatibility */
4757dd7cddfSDavid du Colombier 			rp->obj = OType;
4767dd7cddfSDavid du Colombier 		else
4777dd7cddfSDavid du Colombier 			parseerror("unknown object %s", word);
4787dd7cddfSDavid du Colombier 	}
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier 	/* verb */
4817dd7cddfSDavid du Colombier 	while(*p==' ' || *p=='\t')
4827dd7cddfSDavid du Colombier 		p++;
4837dd7cddfSDavid du Colombier 	for(word=p; *p!=' ' && *p!='\t'; p++)
4847dd7cddfSDavid du Colombier 		if(*p == '\0')
4857dd7cddfSDavid du Colombier 			parseerror("malformed rule");
4867dd7cddfSDavid du Colombier 	*p++ = '\0';
4877dd7cddfSDavid du Colombier 	rp->verb = lookup(word, verbs);
4887dd7cddfSDavid du Colombier 	if(rp->verb < 0)
4897dd7cddfSDavid du Colombier 		parseerror("unknown verb %s", word);
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier 	/* argument */
4927dd7cddfSDavid du Colombier 	while(*p==' ' || *p=='\t')
4937dd7cddfSDavid du Colombier 		p++;
4947dd7cddfSDavid du Colombier 	if(*p == '\0')
4957dd7cddfSDavid du Colombier 		parseerror("malformed rule");
4967dd7cddfSDavid du Colombier 	rp->arg = estrdup(p);
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	parserule(rp);
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	return rp;
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier void
freerule(Rule * r)5047dd7cddfSDavid du Colombier freerule(Rule *r)
5057dd7cddfSDavid du Colombier {
5067dd7cddfSDavid du Colombier 	free(r->arg);
5077dd7cddfSDavid du Colombier 	free(r->qarg);
5087dd7cddfSDavid du Colombier 	free(r->regex);
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier void
freerules(Rule ** r)5127dd7cddfSDavid du Colombier freerules(Rule **r)
5137dd7cddfSDavid du Colombier {
5147dd7cddfSDavid du Colombier 	while(*r)
5157dd7cddfSDavid du Colombier 		freerule(*r++);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier void
freeruleset(Ruleset * rs)5197dd7cddfSDavid du Colombier freeruleset(Ruleset *rs)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier 	freerules(rs->pat);
5227dd7cddfSDavid du Colombier 	free(rs->pat);
5237dd7cddfSDavid du Colombier 	freerules(rs->act);
5247dd7cddfSDavid du Colombier 	free(rs->act);
5257dd7cddfSDavid du Colombier 	free(rs->port);
5267dd7cddfSDavid du Colombier 	free(rs);
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier Ruleset*
readruleset(void)5307dd7cddfSDavid du Colombier readruleset(void)
5317dd7cddfSDavid du Colombier {
5327dd7cddfSDavid du Colombier 	Ruleset *rs;
5337dd7cddfSDavid du Colombier 	Rule *r;
5347dd7cddfSDavid du Colombier 	int eof, inrule, i, ncmd;
5357dd7cddfSDavid du Colombier 
5367dd7cddfSDavid du Colombier    Again:
5377dd7cddfSDavid du Colombier 	eof = 0;
5387dd7cddfSDavid du Colombier 	rs = emalloc(sizeof(Ruleset));
5397dd7cddfSDavid du Colombier 	rs->pat = emalloc(sizeof(Rule*));
5407dd7cddfSDavid du Colombier 	rs->act = emalloc(sizeof(Rule*));
5417dd7cddfSDavid du Colombier 	inrule = 0;
5427dd7cddfSDavid du Colombier 	ncmd = 0;
5437dd7cddfSDavid du Colombier 	for(;;){
5447dd7cddfSDavid du Colombier 		r = readrule(&eof);
5457dd7cddfSDavid du Colombier 		if(eof)
5467dd7cddfSDavid du Colombier 			break;
5477dd7cddfSDavid du Colombier 		if(r==nil){
5487dd7cddfSDavid du Colombier 			if(inrule)
5497dd7cddfSDavid du Colombier 				break;
5507dd7cddfSDavid du Colombier 			continue;
5517dd7cddfSDavid du Colombier 		}
5527dd7cddfSDavid du Colombier 		inrule = 1;
5537dd7cddfSDavid du Colombier 		switch(r->obj){
5547dd7cddfSDavid du Colombier 		case OArg:
5557dd7cddfSDavid du Colombier 		case OAttr:
5567dd7cddfSDavid du Colombier 		case OData:
5577dd7cddfSDavid du Colombier 		case ODst:
5587dd7cddfSDavid du Colombier 		case OType:
55959cc4ca5SDavid du Colombier 		case OWdir:
5607dd7cddfSDavid du Colombier 		case OSrc:
5617dd7cddfSDavid du Colombier 			rs->npat++;
5627dd7cddfSDavid du Colombier 			rs->pat = erealloc(rs->pat, (rs->npat+1)*sizeof(Rule*));
5637dd7cddfSDavid du Colombier 			rs->pat[rs->npat-1] = r;
5647dd7cddfSDavid du Colombier 			rs->pat[rs->npat] = nil;
5657dd7cddfSDavid du Colombier 			break;
5667dd7cddfSDavid du Colombier 		case OPlumb:
5677dd7cddfSDavid du Colombier 			rs->nact++;
5687dd7cddfSDavid du Colombier 			rs->act = erealloc(rs->act, (rs->nact+1)*sizeof(Rule*));
5697dd7cddfSDavid du Colombier 			rs->act[rs->nact-1] = r;
5707dd7cddfSDavid du Colombier 			rs->act[rs->nact] = nil;
5717dd7cddfSDavid du Colombier 			if(r->verb == VTo){
5727dd7cddfSDavid du Colombier 				if(rs->npat>0 && rs->port != nil)	/* npat==0 implies port declaration */
5737dd7cddfSDavid du Colombier 					parseerror("too many ports");
5747dd7cddfSDavid du Colombier 				if(lookup(r->qarg, badports) >= 0)
5757dd7cddfSDavid du Colombier 					parseerror("illegal port name %s", r->qarg);
576*9b7bf7dfSDavid du Colombier 				if(rs->port)
577*9b7bf7dfSDavid du Colombier 					free(rs->port);
5787dd7cddfSDavid du Colombier 				rs->port = estrdup(r->qarg);
5797dd7cddfSDavid du Colombier 			}else
5807dd7cddfSDavid du Colombier 				ncmd++;	/* start or client rule */
5817dd7cddfSDavid du Colombier 			break;
5827dd7cddfSDavid du Colombier 		}
5837dd7cddfSDavid du Colombier 	}
5847dd7cddfSDavid du Colombier 	if(ncmd > 1){
5857dd7cddfSDavid du Colombier 		freeruleset(rs);
5867dd7cddfSDavid du Colombier 		parseerror("ruleset has more than one client or start action");
5877dd7cddfSDavid du Colombier 	}
5887dd7cddfSDavid du Colombier 	if(rs->npat>0 && rs->nact>0)
5897dd7cddfSDavid du Colombier 		return rs;
5907dd7cddfSDavid du Colombier 	if(rs->npat==0 && rs->nact==0){
5917dd7cddfSDavid du Colombier 		freeruleset(rs);
5927dd7cddfSDavid du Colombier 		return nil;
5937dd7cddfSDavid du Colombier 	}
5947dd7cddfSDavid du Colombier 	if(rs->nact==0 || rs->port==nil){
5957dd7cddfSDavid du Colombier 		freeruleset(rs);
5967dd7cddfSDavid du Colombier 		parseerror("ruleset must have patterns and actions");
5977dd7cddfSDavid du Colombier 		return nil;
5987dd7cddfSDavid du Colombier 	}
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier 	/* declare ports */
6017dd7cddfSDavid du Colombier 	for(i=0; i<rs->nact; i++)
6027dd7cddfSDavid du Colombier 		if(rs->act[i]->verb != VTo){
6037dd7cddfSDavid du Colombier 			freeruleset(rs);
6047dd7cddfSDavid du Colombier 			parseerror("ruleset must have actions");
6057dd7cddfSDavid du Colombier 			return nil;
6067dd7cddfSDavid du Colombier 		}
6077dd7cddfSDavid du Colombier 	for(i=0; i<rs->nact; i++)
6087dd7cddfSDavid du Colombier 		addport(rs->act[i]->qarg);
6097dd7cddfSDavid du Colombier 	freeruleset(rs);
6107dd7cddfSDavid du Colombier 	goto Again;
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier Ruleset**
readrules(char * name,int fd)6147dd7cddfSDavid du Colombier readrules(char *name, int fd)
6157dd7cddfSDavid du Colombier {
6167dd7cddfSDavid du Colombier 	Ruleset *rs, **rules;
6177dd7cddfSDavid du Colombier 	int n;
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	parsing = 1;
6207dd7cddfSDavid du Colombier 	pushinput(name, fd, nil);
6217dd7cddfSDavid du Colombier 	rules = emalloc(sizeof(Ruleset*));
6227dd7cddfSDavid du Colombier 	for(n=0; (rs=readruleset())!=nil; n++){
6237dd7cddfSDavid du Colombier 		rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
6247dd7cddfSDavid du Colombier 		rules[n] = rs;
6257dd7cddfSDavid du Colombier 		rules[n+1] = nil;
6267dd7cddfSDavid du Colombier 	}
6277dd7cddfSDavid du Colombier 	popinput();
6287dd7cddfSDavid du Colombier 	parsing = 0;
6297dd7cddfSDavid du Colombier 	return rules;
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier 
6327dd7cddfSDavid du Colombier char*
concat(char * s,char * t)6337dd7cddfSDavid du Colombier concat(char *s, char *t)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier 	if(t == nil)
6367dd7cddfSDavid du Colombier 		return s;
6377dd7cddfSDavid du Colombier 	if(s == nil)
6387dd7cddfSDavid du Colombier 		s = estrdup(t);
6397dd7cddfSDavid du Colombier 	else{
6407dd7cddfSDavid du Colombier 		s = erealloc(s, strlen(s)+strlen(t)+1);
6417dd7cddfSDavid du Colombier 		strcat(s, t);
6427dd7cddfSDavid du Colombier 	}
6437dd7cddfSDavid du Colombier 	return s;
6447dd7cddfSDavid du Colombier }
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier char*
printpat(Rule * r)6477dd7cddfSDavid du Colombier printpat(Rule *r)
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier 	char *s;
6507dd7cddfSDavid du Colombier 
6517dd7cddfSDavid du Colombier 	s = emalloc(strlen(objects[r->obj])+1+strlen(verbs[r->verb])+1+strlen(r->arg)+1+1);
6527dd7cddfSDavid du Colombier 	sprint(s, "%s\t%s\t%s\n", objects[r->obj], verbs[r->verb], r->arg);
6537dd7cddfSDavid du Colombier 	return s;
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier char*
printvar(Var * v)6577dd7cddfSDavid du Colombier printvar(Var *v)
6587dd7cddfSDavid du Colombier {
6597dd7cddfSDavid du Colombier 	char *s;
6607dd7cddfSDavid du Colombier 
6617dd7cddfSDavid du Colombier 	s = emalloc(strlen(v->name)+1+strlen(v->value)+2+1);
6627dd7cddfSDavid du Colombier 	sprint(s, "%s=%s\n\n", v->name, v->value);
6637dd7cddfSDavid du Colombier 	return s;
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier char*
printrule(Ruleset * r)6677dd7cddfSDavid du Colombier printrule(Ruleset *r)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier 	int i;
6707dd7cddfSDavid du Colombier 	char *s;
6717dd7cddfSDavid du Colombier 
6727dd7cddfSDavid du Colombier 	s = nil;
6737dd7cddfSDavid du Colombier 	for(i=0; i<r->npat; i++)
6747dd7cddfSDavid du Colombier 		s = concat(s, printpat(r->pat[i]));
6757dd7cddfSDavid du Colombier 	for(i=0; i<r->nact; i++)
6767dd7cddfSDavid du Colombier 		s = concat(s, printpat(r->act[i]));
6777dd7cddfSDavid du Colombier 	s = concat(s, "\n");
6787dd7cddfSDavid du Colombier 	return s;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier 
6817dd7cddfSDavid du Colombier char*
printport(char * port)6827dd7cddfSDavid du Colombier printport(char *port)
6837dd7cddfSDavid du Colombier {
6847dd7cddfSDavid du Colombier 	char *s;
6857dd7cddfSDavid du Colombier 
6867dd7cddfSDavid du Colombier 	s = nil;
6877dd7cddfSDavid du Colombier 	s = concat(s, "plumb to ");
6887dd7cddfSDavid du Colombier 	s = concat(s, port);
6897dd7cddfSDavid du Colombier 	s = concat(s, "\n");
6907dd7cddfSDavid du Colombier 	return s;
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier 
6937dd7cddfSDavid du Colombier char*
printrules(void)6947dd7cddfSDavid du Colombier printrules(void)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier 	int i;
6977dd7cddfSDavid du Colombier 	char *s;
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	s = nil;
7007dd7cddfSDavid du Colombier 	for(i=0; i<nvars; i++)
7017dd7cddfSDavid du Colombier 		s = concat(s, printvar(&vars[i]));
7027dd7cddfSDavid du Colombier 	for(i=0; i<nports; i++)
7037dd7cddfSDavid du Colombier 		s = concat(s, printport(ports[i]));
7047dd7cddfSDavid du Colombier 	s = concat(s, "\n");
7057dd7cddfSDavid du Colombier 	for(i=0; rules[i]; i++)
7067dd7cddfSDavid du Colombier 		s = concat(s, printrule(rules[i]));
7077dd7cddfSDavid du Colombier 	return s;
7087dd7cddfSDavid du Colombier }
7097dd7cddfSDavid du Colombier 
7107dd7cddfSDavid du Colombier char*
stringof(char * s,int n)7117dd7cddfSDavid du Colombier stringof(char *s, int n)
7127dd7cddfSDavid du Colombier {
7137dd7cddfSDavid du Colombier 	char *t;
7147dd7cddfSDavid du Colombier 
7157dd7cddfSDavid du Colombier 	t = emalloc(n+1);
7167dd7cddfSDavid du Colombier 	memmove(t, s, n);
7177dd7cddfSDavid du Colombier 	return t;
7187dd7cddfSDavid du Colombier }
7197dd7cddfSDavid du Colombier 
7207dd7cddfSDavid du Colombier uchar*
morerules(uchar * text,int done)7217dd7cddfSDavid du Colombier morerules(uchar *text, int done)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier 	int n;
7247dd7cddfSDavid du Colombier 	Ruleset *rs;
7257dd7cddfSDavid du Colombier 	uchar *otext, *s, *endofrule;
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier 	pushinput("<rules input>", -1, text);
7287dd7cddfSDavid du Colombier 	if(done)
7297dd7cddfSDavid du Colombier 		input->end = text+strlen((char*)text);
7307dd7cddfSDavid du Colombier 	else{
7317dd7cddfSDavid du Colombier 		/*
7327dd7cddfSDavid du Colombier 		 * Help user by sending any full rules to parser so any parse errors will
7337dd7cddfSDavid du Colombier 		 * occur on write rather than close. A heuristic will do: blank line ends rule.
7347dd7cddfSDavid du Colombier 		 */
7357dd7cddfSDavid du Colombier 		endofrule = nil;
7367dd7cddfSDavid du Colombier 		for(s=text; *s!='\0'; s++)
7377dd7cddfSDavid du Colombier 			if(*s=='\n' && *++s=='\n')
7387dd7cddfSDavid du Colombier 				endofrule = s+1;
7397dd7cddfSDavid du Colombier 		if(endofrule == nil)
7407dd7cddfSDavid du Colombier 			return text;
7417dd7cddfSDavid du Colombier 		input->end = endofrule;
7427dd7cddfSDavid du Colombier 	}
7437dd7cddfSDavid du Colombier 	for(n=0; rules[n]; n++)
7447dd7cddfSDavid du Colombier 		;
7457dd7cddfSDavid du Colombier 	while((rs=readruleset()) != nil){
7467dd7cddfSDavid du Colombier 		rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
7477dd7cddfSDavid du Colombier 		rules[n++] = rs;
7487dd7cddfSDavid du Colombier 		rules[n] = nil;
7497dd7cddfSDavid du Colombier 	}
7507dd7cddfSDavid du Colombier 	otext =text;
7517dd7cddfSDavid du Colombier 	if(input == nil)
7527dd7cddfSDavid du Colombier 		text = (uchar*)estrdup("");
7537dd7cddfSDavid du Colombier 	else
7547dd7cddfSDavid du Colombier 		text = (uchar*)estrdup((char*)input->end);
7557dd7cddfSDavid du Colombier 	popinput();
7567dd7cddfSDavid du Colombier 	free(otext);
7577dd7cddfSDavid du Colombier 	return text;
7587dd7cddfSDavid du Colombier }
7597dd7cddfSDavid du Colombier 
7607dd7cddfSDavid du Colombier char*
writerules(char * s,int n)7617dd7cddfSDavid du Colombier writerules(char *s, int n)
7627dd7cddfSDavid du Colombier {
7637dd7cddfSDavid du Colombier 	static uchar *text;
7647dd7cddfSDavid du Colombier 	char *tmp;
7657dd7cddfSDavid du Colombier 
7667dd7cddfSDavid du Colombier 	free(lasterror);
7677dd7cddfSDavid du Colombier 	lasterror = nil;
7687dd7cddfSDavid du Colombier 	parsing = 1;
7697dd7cddfSDavid du Colombier 	if(setjmp(parsejmp) == 0){
7707dd7cddfSDavid du Colombier 		tmp = stringof(s, n);
7717dd7cddfSDavid du Colombier 		text = (uchar*)concat((char*)text, tmp);
7727dd7cddfSDavid du Colombier 		free(tmp);
7737dd7cddfSDavid du Colombier 		text = morerules(text, s==nil);
7747dd7cddfSDavid du Colombier 	}
7757dd7cddfSDavid du Colombier 	if(s == nil){
7767dd7cddfSDavid du Colombier 		free(text);
7777dd7cddfSDavid du Colombier 		text = nil;
7787dd7cddfSDavid du Colombier 	}
7797dd7cddfSDavid du Colombier 	parsing = 0;
7807dd7cddfSDavid du Colombier 	makeports(rules);
7817dd7cddfSDavid du Colombier 	return lasterror;
7827dd7cddfSDavid du Colombier }
783