9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

parse.c (5593B)


      1 #include	"mk.h"
      2 
      3 char *infile;
      4 int mkinline;
      5 static int rhead(char *, Word **, Word **, int *, char **);
      6 static char *rbody(Biobuf*);
      7 extern Word *target1;
      8 
      9 void
     10 parse(char *f, int fd, int varoverride)
     11 {
     12 	int hline;
     13 	char *body;
     14 	Word *head, *tail;
     15 	int attr, set, pid;
     16 	char *prog, *p;
     17 	int newfd;
     18 	Biobuf in;
     19 	Bufblock *buf;
     20 	char *err;
     21 
     22 	if(fd < 0){
     23 		fprint(2, "open %s: %r\n", f);
     24 		Exit();
     25 	}
     26 	pushshell();
     27 	ipush();
     28 	infile = strdup(f);
     29 	mkinline = 1;
     30 	Binit(&in, fd, OREAD);
     31 	buf = newbuf();
     32 	while(assline(&in, buf)){
     33 		hline = mkinline;
     34 		switch(rhead(buf->start, &head, &tail, &attr, &prog))
     35 		{
     36 		case '<':
     37 			p = wtos(tail, ' ');
     38 			if(*p == 0){
     39 				SYNERR(-1);
     40 				fprint(2, "missing include file name\n");
     41 				Exit();
     42 			}
     43 			newfd = open(p, OREAD);
     44 			if(newfd < 0){
     45 				fprint(2, "warning: skipping missing include file %s: %r\n", p);
     46 			} else
     47 				parse(p, newfd, 0);
     48 			break;
     49 		case '|':
     50 			p = wtos(tail, ' ');
     51 			if(*p == 0){
     52 				SYNERR(-1);
     53 				fprint(2, "missing include program name\n");
     54 				Exit();
     55 			}
     56 			execinit();
     57 			pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
     58 			if(newfd < 0){
     59 				fprint(2, "warning: skipping missing program file %s: %r\n", p);
     60 			} else
     61 				parse(p, newfd, 0);
     62 			while(waitup(-3, &pid) >= 0)
     63 				;
     64 			if(pid != 0){
     65 				fprint(2, "bad include program status\n");
     66 				Exit();
     67 			}
     68 			break;
     69 		case ':':
     70 			body = rbody(&in);
     71 			addrules(head, tail, body, attr, hline, prog);
     72 			break;
     73 		case '=':
     74 			if(head->next){
     75 				SYNERR(-1);
     76 				fprint(2, "multiple vars on left side of assignment\n");
     77 				Exit();
     78 			}
     79 			if(symlook(head->s, S_OVERRIDE, 0)){
     80 				set = varoverride;
     81 			} else {
     82 				set = 1;
     83 				if(varoverride)
     84 					symlook(head->s, S_OVERRIDE, (void *)"");
     85 			}
     86 			if(set){
     87 /*
     88 char *cp;
     89 dumpw("tail", tail);
     90 cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
     91 */
     92 				setvar(head->s, (void *) tail);
     93 				symlook(head->s, S_WESET, (void *)"");
     94 				if(strcmp(head->s, "MKSHELL") == 0){
     95 					if((err = setshell(tail)) != nil){
     96 						SYNERR(hline);
     97 						fprint(2, "%s\n", err);
     98 						Exit();
     99 						break;
    100 					}
    101 				}
    102 			}
    103 			if(attr)
    104 				symlook(head->s, S_NOEXPORT, (void *)"");
    105 			break;
    106 		default:
    107 			SYNERR(hline);
    108 			fprint(2, "expected one of :<=\n");
    109 			Exit();
    110 			break;
    111 		}
    112 	}
    113 	close(fd);
    114 	freebuf(buf);
    115 	ipop();
    116 	popshell();
    117 }
    118 
    119 void
    120 addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
    121 {
    122 	Word *w;
    123 
    124 	assert("addrules args", head && body);
    125 		/* tuck away first non-meta rule as default target*/
    126 	if(target1 == 0 && !(attr&REGEXP)){
    127 		for(w = head; w; w = w->next)
    128 			if(shellt->charin(w->s, "%&"))
    129 				break;
    130 		if(w == 0)
    131 			target1 = wdup(head);
    132 	}
    133 	for(w = head; w; w = w->next)
    134 		addrule(w->s, tail, body, head, attr, hline, prog);
    135 }
    136 
    137 static int
    138 rhead(char *line, Word **h, Word **t, int *attr, char **prog)
    139 {
    140 	char *p;
    141 	char *pp;
    142 	int sep;
    143 	Rune r;
    144 	int n;
    145 	Word *w;
    146 
    147 	p = shellt->charin(line,":=<");
    148 	if(p == 0)
    149 		return('?');
    150 	sep = *p;
    151 	*p++ = 0;
    152 	if(sep == '<' && *p == '|'){
    153 		sep = '|';
    154 		p++;
    155 	}
    156 	*attr = 0;
    157 	*prog = 0;
    158 	if(sep == '='){
    159 		pp = shellt->charin(p, shellt->termchars);	/* termchars is shell-dependent */
    160 		if (pp && *pp == '=') {
    161 			while (p != pp) {
    162 				n = chartorune(&r, p);
    163 				switch(r)
    164 				{
    165 				default:
    166 					SYNERR(-1);
    167 					fprint(2, "unknown attribute '%c'\n",*p);
    168 					Exit();
    169 				case 'U':
    170 					*attr = 1;
    171 					break;
    172 				}
    173 				p += n;
    174 			}
    175 			p++;		/* skip trailing '=' */
    176 		}
    177 	}
    178 	if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
    179 		while (*p) {
    180 			n = chartorune(&r, p);
    181 			if (r == ':')
    182 				break;
    183 			p += n;
    184 			switch(r)
    185 			{
    186 			default:
    187 				SYNERR(-1);
    188 				fprint(2, "unknown attribute '%c'\n", p[-1]);
    189 				Exit();
    190 			case 'D':
    191 				*attr |= DEL;
    192 				break;
    193 			case 'E':
    194 				*attr |= NOMINUSE;
    195 				break;
    196 			case 'n':
    197 				*attr |= NOVIRT;
    198 				break;
    199 			case 'N':
    200 				*attr |= NOREC;
    201 				break;
    202 			case 'P':
    203 				pp = utfrune(p, ':');
    204 				if (pp == 0 || *pp == 0)
    205 					goto eos;
    206 				*pp = 0;
    207 				*prog = strdup(p);
    208 				*pp = ':';
    209 				p = pp;
    210 				break;
    211 			case 'Q':
    212 				*attr |= QUIET;
    213 				break;
    214 			case 'R':
    215 				*attr |= REGEXP;
    216 				break;
    217 			case 'U':
    218 				*attr |= UPD;
    219 				break;
    220 			case 'V':
    221 				*attr |= VIR;
    222 				break;
    223 			}
    224 		}
    225 		if (*p++ != ':') {
    226 	eos:
    227 			SYNERR(-1);
    228 			fprint(2, "missing trailing :\n");
    229 			Exit();
    230 		}
    231 	}
    232 	*h = w = stow(line);
    233 	if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
    234 		SYNERR(mkinline-1);
    235 		fprint(2, "no var on left side of assignment/rule\n");
    236 		Exit();
    237 	}
    238 	*t = stow(p);
    239 	return(sep);
    240 }
    241 
    242 static char *
    243 rbody(Biobuf *in)
    244 {
    245 	Bufblock *buf;
    246 	int r, lastr;
    247 	char *p;
    248 
    249 	lastr = '\n';
    250 	buf = newbuf();
    251 	for(;;){
    252 		r = Bgetrune(in);
    253 		if (r < 0)
    254 			break;
    255 		if (lastr == '\n') {
    256 			if (r == '#')
    257 				rinsert(buf, r);
    258 			else if (r != ' ' && r != '\t') {
    259 				Bungetrune(in);
    260 				break;
    261 			}
    262 		} else
    263 			rinsert(buf, r);
    264 		lastr = r;
    265 		if (r == '\n')
    266 			mkinline++;
    267 	}
    268 	insert(buf, 0);
    269 	p = strdup(buf->start);
    270 	freebuf(buf);
    271 	return p;
    272 }
    273 
    274 struct input
    275 {
    276 	char *file;
    277 	int line;
    278 	struct input *next;
    279 };
    280 static struct input *inputs = 0;
    281 
    282 void
    283 ipush(void)
    284 {
    285 	struct input *in, *me;
    286 
    287 	me = (struct input *)Malloc(sizeof(*me));
    288 	me->file = infile;
    289 	me->line = mkinline;
    290 	me->next = 0;
    291 	if(inputs == 0)
    292 		inputs = me;
    293 	else {
    294 		for(in = inputs; in->next; )
    295 			in = in->next;
    296 		in->next = me;
    297 	}
    298 }
    299 
    300 void
    301 ipop(void)
    302 {
    303 	struct input *in, *me;
    304 
    305 	assert("pop input list", inputs != 0);
    306 	if(inputs->next == 0){
    307 		me = inputs;
    308 		inputs = 0;
    309 	} else {
    310 		for(in = inputs; in->next->next; )
    311 			in = in->next;
    312 		me = in->next;
    313 		in->next = 0;
    314 	}
    315 	infile = me->file;
    316 	mkinline = me->line;
    317 	free((char *)me);
    318 }