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®EXP)){ 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 }