Introduction
Introduction Statistics Contact Development Disclaimer Help
cmd.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
cmd.c (10833B)
---
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 struct 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 case '"':
564 error(Eaddress);
565 break;
566 case 'l':
567 case '#':
568 if(addr.type=='"')
569 break;
570 /* fall through */
571 case '/':
572 case '?':
573 if(addr.type!='+' && addr.type!='-'){
574 /* insert the missing '+' */
575 nap = newaddr();
576 nap->type='+';
577 nap->next = addr.next;
578 addr.next = nap;
579 }
580 break;
581 case '+':
582 case '-':
583 break;
584 default:
585 panic("simpleaddr");
586 }
587 ap = newaddr();
588 *ap = addr;
589 return ap;
590 }
591
592 Addr *
593 compoundaddr(void)
594 {
595 Addr addr;
596 Addr *ap, *next;
597
598 addr.left = simpleaddr();
599 if((addr.type = skipbl())!=',' && addr.type!=';')
600 return addr.left;
601 getch();
602 next = addr.next = compoundaddr();
603 if(next && (next->type==',' || next->type==';') && next->left==0)
604 error(Eaddress);
605 ap = newaddr();
606 *ap = addr;
607 return ap;
608 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.