tcmd.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tcmd.c (10921B) | |
--- | |
1 #include "sam.h" | |
2 #include "parse.h" | |
3 | |
4 static char linex[]="\n"; | |
5 static char wordx[]=" \t\n"; | |
6 struct Cmdtab cmdtab[]={ | |
7 /* cmdc text regexp addr defcmd … | |
8 {'\n', 0, 0, 0, 0, aDot, … | |
9 {'a', 1, 0, 0, 0, aDot, … | |
10 {'b', 0, 0, 0, 0, aNo, … | |
11 {'B', 0, 0, 0, 0, aNo, … | |
12 {'c', 1, 0, 0, 0, aDot, … | |
13 {'d', 0, 0, 0, 0, aDot, … | |
14 {'D', 0, 0, 0, 0, aNo, … | |
15 {'e', 0, 0, 0, 0, aNo, … | |
16 {'f', 0, 0, 0, 0, aNo, … | |
17 {'g', 0, 1, 0, 'p', aDot, … | |
18 {'i', 1, 0, 0, 0, aDot, … | |
19 {'k', 0, 0, 0, 0, aDot, … | |
20 {'m', 0, 0, 1, 0, aDot, … | |
21 {'n', 0, 0, 0, 0, aNo, … | |
22 {'p', 0, 0, 0, 0, aDot, … | |
23 {'q', 0, 0, 0, 0, aNo, … | |
24 {'r', 0, 0, 0, 0, aDot, … | |
25 {'s', 0, 1, 0, 0, aDot, … | |
26 {'t', 0, 0, 1, 0, aDot, … | |
27 {'u', 0, 0, 0, 0, aNo, … | |
28 {'v', 0, 1, 0, 'p', aDot, … | |
29 {'w', 0, 0, 0, 0, aAll, … | |
30 {'x', 0, 1, 0, 'p', aDot, … | |
31 {'y', 0, 1, 0, 'p', aDot, … | |
32 {'X', 0, 1, 0, 'f', aNo, … | |
33 {'Y', 0, 1, 0, 'f', aNo, … | |
34 {'!', 0, 0, 0, 0, aNo, … | |
35 {'>', 0, 0, 0, 0, aDot, … | |
36 {'<', 0, 0, 0, 0, aDot, … | |
37 {'|', 0, 0, 0, 0, aDot, … | |
38 {'=', 0, 0, 0, 0, aDot, … | |
39 {'c'|0x100,0, 0, 0, 0, aNo, 0… | |
40 {0, 0, 0, 0, 0, 0, 0, … | |
41 }; | |
42 Cmd *parsecmd(int); | |
43 Addr *compoundaddr(void); | |
44 Addr *simpleaddr(void); | |
45 void freecmd(void); | |
46 void okdelim(int); | |
47 | |
48 Rune line[BLOCKSIZE]; | |
49 Rune termline[BLOCKSIZE]; | |
50 Rune *linep = line; | |
51 Rune *terminp = termline; | |
52 Rune *termoutp = termline; | |
53 | |
54 List cmdlist = { 'p' }; | |
55 List addrlist = { 'p' }; | |
56 List relist = { 'p' }; | |
57 List stringlist = { 'p' }; | |
58 | |
59 int eof; | |
60 | |
61 void | |
62 resetcmd(void) | |
63 { | |
64 linep = line; | |
65 *linep = 0; | |
66 terminp = termoutp = termline; | |
67 freecmd(); | |
68 } | |
69 | |
70 int | |
71 inputc(void) | |
72 { | |
73 int n, nbuf; | |
74 char buf[UTFmax]; | |
75 Rune r; | |
76 | |
77 Again: | |
78 nbuf = 0; | |
79 if(downloaded){ | |
80 while(termoutp == terminp){ | |
81 cmdupdate(); | |
82 if(patset) | |
83 tellpat(); | |
84 while(termlocked > 0){ | |
85 outT0(Hunlock); | |
86 termlocked--; | |
87 } | |
88 if(rcv() == 0) | |
89 return -1; | |
90 } | |
91 r = *termoutp++; | |
92 if(termoutp == terminp) | |
93 terminp = termoutp = termline; | |
94 }else{ | |
95 do{ | |
96 n = read(0, buf+nbuf, 1); | |
97 if(n <= 0) | |
98 return -1; | |
99 nbuf += n; | |
100 }while(!fullrune(buf, nbuf)); | |
101 chartorune(&r, buf); | |
102 } | |
103 if(r == 0){ | |
104 warn(Wnulls); | |
105 goto Again; | |
106 } | |
107 return r; | |
108 } | |
109 | |
110 int | |
111 inputline(void) | |
112 { | |
113 int i, c, start; | |
114 | |
115 /* | |
116 * Could set linep = line and i = 0 here and just | |
117 * error(Etoolong) below, but this way we keep | |
118 * old input buffer history around for a while. | |
119 * This is useful only for debugging. | |
120 */ | |
121 i = linep - line; | |
122 do{ | |
123 if((c = inputc())<=0) | |
124 return -1; | |
125 if(i == nelem(line)-1){ | |
126 if(linep == line) | |
127 error(Etoolong); | |
128 start = linep - line; | |
129 runemove(line, linep, i-start); | |
130 i -= start; | |
131 linep = line; | |
132 } | |
133 }while((line[i++]=c) != '\n'); | |
134 line[i] = 0; | |
135 return 1; | |
136 } | |
137 | |
138 int | |
139 getch(void) | |
140 { | |
141 if(eof) | |
142 return -1; | |
143 if(*linep==0 && inputline()<0){ | |
144 eof = TRUE; | |
145 return -1; | |
146 } | |
147 return *linep++; | |
148 } | |
149 | |
150 int | |
151 nextc(void) | |
152 { | |
153 if(*linep == 0) | |
154 return -1; | |
155 return *linep; | |
156 } | |
157 | |
158 void | |
159 ungetch(void) | |
160 { | |
161 if(--linep < line) | |
162 panic("ungetch"); | |
163 } | |
164 | |
165 Posn | |
166 getnum(int signok) | |
167 { | |
168 Posn n=0; | |
169 int c, sign; | |
170 | |
171 sign = 1; | |
172 if(signok>1 && nextc()=='-'){ | |
173 sign = -1; | |
174 getch(); | |
175 } | |
176 if((c=nextc())<'0' || '9'<c) /* no number defaults to 1 */ | |
177 return sign; | |
178 while('0'<=(c=getch()) && c<='9') | |
179 n = n*10 + (c-'0'); | |
180 ungetch(); | |
181 return sign*n; | |
182 } | |
183 | |
184 int | |
185 skipbl(void) | |
186 { | |
187 int c; | |
188 do | |
189 c = getch(); | |
190 while(c==' ' || c=='\t'); | |
191 if(c >= 0) | |
192 ungetch(); | |
193 return c; | |
194 } | |
195 | |
196 void | |
197 termcommand(void) | |
198 { | |
199 Posn p; | |
200 | |
201 for(p=cmdpt; p<cmd->b.nc; p++){ | |
202 if(terminp >= &termline[BLOCKSIZE]){ | |
203 cmdpt = cmd->b.nc; | |
204 error(Etoolong); | |
205 } | |
206 *terminp++ = filereadc(cmd, p); | |
207 } | |
208 cmdpt = cmd->b.nc; | |
209 } | |
210 | |
211 void | |
212 cmdloop(void) | |
213 { | |
214 Cmd *cmdp; | |
215 File *ocurfile; | |
216 int loaded; | |
217 | |
218 for(;;){ | |
219 if(!downloaded && curfile && curfile->unread) | |
220 load(curfile); | |
221 if((cmdp = parsecmd(0))==0){ | |
222 if(downloaded){ | |
223 rescue(); | |
224 exits("eof"); | |
225 } | |
226 break; | |
227 } | |
228 ocurfile = curfile; | |
229 loaded = curfile && !curfile->unread; | |
230 if(cmdexec(curfile, cmdp) == 0) | |
231 break; | |
232 freecmd(); | |
233 cmdupdate(); | |
234 update(); | |
235 if(downloaded && curfile && | |
236 (ocurfile!=curfile || (!loaded && !curfile->unread))) | |
237 outTs(Hcurrent, curfile->tag); | |
238 /* don't allow type ahead on files that aren't b… | |
239 if(downloaded && curfile && curfile->rasp == 0) | |
240 terminp = termoutp; | |
241 } | |
242 } | |
243 | |
244 Cmd * | |
245 newcmd(void){ | |
246 Cmd *p; | |
247 | |
248 p = emalloc(sizeof(Cmd)); | |
249 inslist(&cmdlist, cmdlist.nused, (long)p); | |
250 return p; | |
251 } | |
252 | |
253 Addr* | |
254 newaddr(void) | |
255 { | |
256 Addr *p; | |
257 | |
258 p = emalloc(sizeof(Addr)); | |
259 inslist(&addrlist, addrlist.nused, (long)p); | |
260 return p; | |
261 } | |
262 | |
263 String* | |
264 newre(void) | |
265 { | |
266 String *p; | |
267 | |
268 p = emalloc(sizeof(String)); | |
269 inslist(&relist, relist.nused, (long)p); | |
270 Strinit(p); | |
271 return p; | |
272 } | |
273 | |
274 String* | |
275 newstring(void) | |
276 { | |
277 String *p; | |
278 | |
279 p = emalloc(sizeof(String)); | |
280 inslist(&stringlist, stringlist.nused, (long)p); | |
281 Strinit(p); | |
282 return p; | |
283 } | |
284 | |
285 void | |
286 freecmd(void) | |
287 { | |
288 int i; | |
289 | |
290 while(cmdlist.nused > 0) | |
291 free(cmdlist.voidpptr[--cmdlist.nused]); | |
292 while(addrlist.nused > 0) | |
293 free(addrlist.voidpptr[--addrlist.nused]); | |
294 while(relist.nused > 0){ | |
295 i = --relist.nused; | |
296 Strclose(relist.stringpptr[i]); | |
297 free(relist.stringpptr[i]); | |
298 } | |
299 while(stringlist.nused>0){ | |
300 i = --stringlist.nused; | |
301 Strclose(stringlist.stringpptr[i]); | |
302 free(stringlist.stringpptr[i]); | |
303 } | |
304 } | |
305 | |
306 int | |
307 lookup(int c) | |
308 { | |
309 int i; | |
310 | |
311 for(i=0; cmdtab[i].cmdc; i++) | |
312 if(cmdtab[i].cmdc == c) | |
313 return i; | |
314 return -1; | |
315 } | |
316 | |
317 void | |
318 okdelim(int c) | |
319 { | |
320 if(c=='\\' || ('a'<=c && c<='z') | |
321 || ('A'<=c && c<='Z') || ('0'<=c && c<='9')) | |
322 error_c(Edelim, c); | |
323 } | |
324 | |
325 void | |
326 atnl(void) | |
327 { | |
328 skipbl(); | |
329 if(getch() != '\n') | |
330 error(Enewline); | |
331 } | |
332 | |
333 void | |
334 getrhs(String *s, int delim, int cmd) | |
335 { | |
336 int c; | |
337 | |
338 while((c = getch())>0 && c!=delim && c!='\n'){ | |
339 if(c == '\\'){ | |
340 if((c=getch()) <= 0) | |
341 error(Ebadrhs); | |
342 if(c == '\n'){ | |
343 ungetch(); | |
344 c='\\'; | |
345 }else if(c == 'n') | |
346 c='\n'; | |
347 else if(c!=delim && (cmd=='s' || c!='\\')) … | |
348 Straddc(s, '\\'); | |
349 } | |
350 Straddc(s, c); | |
351 } | |
352 ungetch(); /* let client read whether delimeter, '\n' or … | |
353 } | |
354 | |
355 String * | |
356 collecttoken(char *end) | |
357 { | |
358 String *s = newstring(); | |
359 int c; | |
360 | |
361 while((c=nextc())==' ' || c=='\t') | |
362 Straddc(s, getch()); /* blanks significant for getname()… | |
363 while((c=getch())>0 && utfrune(end, c)==0) | |
364 Straddc(s, c); | |
365 Straddc(s, 0); | |
366 if(c != '\n') | |
367 atnl(); | |
368 return s; | |
369 } | |
370 | |
371 String * | |
372 collecttext(void) | |
373 { | |
374 String *s = newstring(); | |
375 int begline, i, c, delim; | |
376 | |
377 if(skipbl()=='\n'){ | |
378 getch(); | |
379 i = 0; | |
380 do{ | |
381 begline = i; | |
382 while((c = getch())>0 && c!='\n') | |
383 i++, Straddc(s, c); | |
384 i++, Straddc(s, '\n'); | |
385 if(c < 0) | |
386 goto Return; | |
387 }while(s->s[begline]!='.' || s->s[begline+1]!='\n'); | |
388 Strdelete(s, s->n-2, s->n); | |
389 }else{ | |
390 okdelim(delim = getch()); | |
391 getrhs(s, delim, 'a'); | |
392 if(nextc()==delim) | |
393 getch(); | |
394 atnl(); | |
395 } | |
396 Return: | |
397 Straddc(s, 0); /* JUST FOR CMDPRINT() */ | |
398 return s; | |
399 } | |
400 | |
401 Cmd * | |
402 parsecmd(int nest) | |
403 { | |
404 int i, c; | |
405 Cmdtab *ct; | |
406 Cmd *cp, *ncp; | |
407 Cmd cmd; | |
408 | |
409 cmd.next = cmd.ccmd = 0; | |
410 cmd.re = 0; | |
411 cmd.flag = cmd.num = 0; | |
412 cmd.addr = compoundaddr(); | |
413 if(skipbl() == -1) | |
414 return 0; | |
415 if((c=getch())==-1) | |
416 return 0; | |
417 cmd.cmdc = c; | |
418 if(cmd.cmdc=='c' && nextc()=='d'){ /* sleazy two-characte… | |
419 getch(); /* the 'd' */ | |
420 cmd.cmdc='c'|0x100; | |
421 } | |
422 i = lookup(cmd.cmdc); | |
423 if(i >= 0){ | |
424 if(cmd.cmdc == '\n') | |
425 goto Return; /* let nl_cmd work it all ou… | |
426 ct = &cmdtab[i]; | |
427 if(ct->defaddr==aNo && cmd.addr) | |
428 error(Enoaddr); | |
429 if(ct->count) | |
430 cmd.num = getnum(ct->count); | |
431 if(ct->regexp){ | |
432 /* x without pattern -> .*\n, indicated by cmd.r… | |
433 /* X without pattern is all files */ | |
434 if((ct->cmdc!='x' && ct->cmdc!='X') || | |
435 ((c = nextc())!=' ' && c!='\t' && c!='\n')){ | |
436 skipbl(); | |
437 if((c = getch())=='\n' || c<0) | |
438 error(Enopattern); | |
439 okdelim(c); | |
440 cmd.re = getregexp(c); | |
441 if(ct->cmdc == 's'){ | |
442 cmd.ctext = newstring(); | |
443 getrhs(cmd.ctext, c, 's'); | |
444 if(nextc() == c){ | |
445 getch(); | |
446 if(nextc() == 'g') | |
447 cmd.flag = getch… | |
448 } | |
449 | |
450 } | |
451 } | |
452 } | |
453 if(ct->addr && (cmd.caddr=simpleaddr())==0) | |
454 error(Eaddress); | |
455 if(ct->defcmd){ | |
456 if(skipbl() == '\n'){ | |
457 getch(); | |
458 cmd.ccmd = newcmd(); | |
459 cmd.ccmd->cmdc = ct->defcmd; | |
460 }else if((cmd.ccmd = parsecmd(nest))==0) | |
461 panic("defcmd"); | |
462 }else if(ct->text) | |
463 cmd.ctext = collecttext(); | |
464 else if(ct->token) | |
465 cmd.ctext = collecttoken(ct->token); | |
466 else | |
467 atnl(); | |
468 }else | |
469 switch(cmd.cmdc){ | |
470 case '{': | |
471 cp = 0; | |
472 do{ | |
473 if(skipbl()=='\n') | |
474 getch(); | |
475 ncp = parsecmd(nest+1); | |
476 if(cp) | |
477 cp->next = ncp; | |
478 else | |
479 cmd.ccmd = ncp; | |
480 }while(cp = ncp); | |
481 break; | |
482 case '}': | |
483 atnl(); | |
484 if(nest==0) | |
485 error(Enolbrace); | |
486 return 0; | |
487 default: | |
488 error_c(Eunk, cmd.cmdc); | |
489 } | |
490 Return: | |
491 cp = newcmd(); | |
492 *cp = cmd; | |
493 return cp; | |
494 } | |
495 | |
496 String* /* BUGGERED */ | |
497 getregexp(int delim) | |
498 { | |
499 String *r = newre(); | |
500 int c; | |
501 | |
502 for(Strzero(&genstr); ; Straddc(&genstr, c)) | |
503 if((c = getch())=='\\'){ | |
504 if(nextc()==delim) | |
505 c = getch(); | |
506 else if(nextc()=='\\'){ | |
507 Straddc(&genstr, c); | |
508 c = getch(); | |
509 } | |
510 }else if(c==delim || c=='\n') | |
511 break; | |
512 if(c!=delim && c) | |
513 ungetch(); | |
514 if(genstr.n > 0){ | |
515 patset = TRUE; | |
516 Strduplstr(&lastpat, &genstr); | |
517 Straddc(&lastpat, '\0'); | |
518 } | |
519 if(lastpat.n <= 1) | |
520 error(Epattern); | |
521 Strduplstr(r, &lastpat); | |
522 return r; | |
523 } | |
524 | |
525 Addr * | |
526 simpleaddr(void) | |
527 { | |
528 Addr addr; | |
529 Addr *ap, *nap; | |
530 | |
531 addr.next = 0; | |
532 addr.left = 0; | |
533 addr.num = 0; | |
534 switch(skipbl()){ | |
535 case '#': | |
536 addr.type = getch(); | |
537 addr.num = getnum(1); | |
538 break; | |
539 case '0': case '1': case '2': case '3': case '4': | |
540 case '5': case '6': case '7': case '8': case '9': | |
541 addr.num = getnum(1); | |
542 addr.type='l'; | |
543 break; | |
544 case '/': case '?': case '"': | |
545 addr.are = getregexp(addr.type = getch()); | |
546 break; | |
547 case '.': | |
548 case '$': | |
549 case '+': | |
550 case '-': | |
551 case '\'': | |
552 addr.type = getch(); | |
553 break; | |
554 default: | |
555 return 0; | |
556 } | |
557 if(addr.next = simpleaddr()) | |
558 switch(addr.next->type){ | |
559 case '.': | |
560 case '$': | |
561 case '\'': | |
562 if(addr.type=='"') | |
563 break; | |
564 /* fall through */ | |
565 case '"': | |
566 error(Eaddress); | |
567 break; | |
568 case 'l': | |
569 case '#': | |
570 if(addr.type=='"') | |
571 break; | |
572 /* fall through */ | |
573 case '/': | |
574 case '?': | |
575 if(addr.type!='+' && addr.type!='-'){ | |
576 /* insert the missing '+' */ | |
577 nap = newaddr(); | |
578 nap->type='+'; | |
579 nap->next = addr.next; | |
580 addr.next = nap; | |
581 } | |
582 break; | |
583 case '+': | |
584 case '-': | |
585 break; | |
586 default: | |
587 panic("simpleaddr"); | |
588 } | |
589 ap = newaddr(); | |
590 *ap = addr; | |
591 return ap; | |
592 } | |
593 | |
594 Addr * | |
595 compoundaddr(void) | |
596 { | |
597 Addr addr; | |
598 Addr *ap, *next; | |
599 | |
600 addr.left = simpleaddr(); | |
601 if((addr.type = skipbl())!=',' && addr.type!=';') | |
602 return addr.left; | |
603 getch(); | |
604 next = addr.next = compoundaddr(); | |
605 if(next && (next->type==',' || next->type==';') && next->left==0) | |
606 error(Eaddress); | |
607 ap = newaddr(); | |
608 *ap = addr; | |
609 return ap; | |
610 } |