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 defaddr count token fn */ 8 '\n', 0, 0, 0, 0, aDot, 0, 0, nl_cmd, 9 'a', 1, 0, 0, 0, aDot, 0, 0, a_cmd, 10 'b', 0, 0, 0, 0, aNo, 0, linex, b_cmd, 11 'B', 0, 0, 0, 0, aNo, 0, linex, b_cmd, 12 'c', 1, 0, 0, 0, aDot, 0, 0, c_cmd, 13 'd', 0, 0, 0, 0, aDot, 0, 0, d_cmd, 14 'D', 0, 0, 0, 0, aNo, 0, linex, D_cmd, 15 'e', 0, 0, 0, 0, aNo, 0, wordx, e_cmd, 16 'f', 0, 0, 0, 0, aNo, 0, wordx, f_cmd, 17 'g', 0, 1, 0, 'p', aDot, 0, 0, g_cmd, 18 'i', 1, 0, 0, 0, aDot, 0, 0, i_cmd, 19 'k', 0, 0, 0, 0, aDot, 0, 0, k_cmd, 20 'm', 0, 0, 1, 0, aDot, 0, 0, m_cmd, 21 'n', 0, 0, 0, 0, aNo, 0, 0, n_cmd, 22 'p', 0, 0, 0, 0, aDot, 0, 0, p_cmd, 23 'q', 0, 0, 0, 0, aNo, 0, 0, q_cmd, 24 'r', 0, 0, 0, 0, aDot, 0, wordx, e_cmd, 25 's', 0, 1, 0, 0, aDot, 1, 0, s_cmd, 26 't', 0, 0, 1, 0, aDot, 0, 0, m_cmd, 27 'u', 0, 0, 0, 0, aNo, 2, 0, u_cmd, 28 'v', 0, 1, 0, 'p', aDot, 0, 0, g_cmd, 29 'w', 0, 0, 0, 0, aAll, 0, wordx, w_cmd, 30 'x', 0, 1, 0, 'p', aDot, 0, 0, x_cmd, 31 'y', 0, 1, 0, 'p', aDot, 0, 0, x_cmd, 32 'X', 0, 1, 0, 'f', aNo, 0, 0, X_cmd, 33 'Y', 0, 1, 0, 'f', aNo, 0, 0, X_cmd, 34 '!', 0, 0, 0, 0, aNo, 0, linex, plan9_cmd, 35 '>', 0, 0, 0, 0, aDot, 0, linex, plan9_cmd, 36 '<', 0, 0, 0, 0, aDot, 0, linex, plan9_cmd, 37 '|', 0, 0, 0, 0, aDot, 0, linex, plan9_cmd, 38 '=', 0, 0, 0, 0, aDot, 0, linex, eq_cmd, 39 'c'|0x100,0, 0, 0, 0, aNo, 0, wordx, cd_cmd, 40 0, 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 bound */ 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!='\\')) /* s does its own */ 348 Straddc(s, '\\'); 349 } 350 Straddc(s, c); 351 } 352 ungetch(); /* let client read whether delimeter, '\n' or whatever */ 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-character case */ 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 out */ 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.re==0 */ 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 }