1#define Extern extern 2#include <sys/types.h> 3#include <sys/stat.h> 4#include <dirent.h> 5#include <limits.h> 6#include <signal.h> 7#define _NSIG NSIG 8#include <errno.h> 9#include <setjmp.h> 10#include "sh.h" 11 12/* -------- eval.c -------- */ 13/* #include "sh.h" */ 14/* #include "word.h" */ 15 16/* 17 * ${} 18 * `command` 19 * blank interpretation 20 * quoting 21 * glob 22 */ 23 24_PROTOTYPE(static int expand, (char *cp, struct wdblock **wbp, int f )); 25_PROTOTYPE(static char *blank, (int f )); 26_PROTOTYPE(static int dollar, (int quoted )); 27_PROTOTYPE(static int grave, (int quoted )); 28_PROTOTYPE(void globname, (char *we, char *pp )); 29_PROTOTYPE(static char *generate, (char *start1, char *end1, char *middle, char *end )); 30_PROTOTYPE(static int anyspcl, (struct wdblock *wb )); 31_PROTOTYPE(static int xstrcmp, (char *p1, char *p2 )); 32_PROTOTYPE(void glob0, (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *))); 33_PROTOTYPE(void glob1, (char *base, char *lim )); 34_PROTOTYPE(void glob2, (char *i, char *j )); 35_PROTOTYPE(void glob3, (char *i, char *j, char *k )); 36_PROTOTYPE(char *memcopy, (char *ato, char *from, int nb )); 37 38char ** 39eval(ap, f) 40register char **ap; 41int f; 42{ 43 struct wdblock *wb; 44 char **wp; 45 char **wf; 46 jmp_buf ev; 47 48 wp = NULL; 49 wb = NULL; 50 wf = NULL; 51 if (newenv(setjmp(errpt = ev)) == 0) { 52 while (*ap && isassign(*ap)) 53 expand(*ap++, &wb, f & ~DOGLOB); 54 if (flag['k']) { 55 for (wf = ap; *wf; wf++) { 56 if (isassign(*wf)) 57 expand(*wf, &wb, f & ~DOGLOB); 58 } 59 } 60 for (wb = addword((char *)0, wb); *ap; ap++) { 61 if (!flag['k'] || !isassign(*ap)) 62 expand(*ap, &wb, f & ~DOKEY); 63 } 64 wb = addword((char *)0, wb); 65 wp = getwords(wb); 66 quitenv(); 67 } else 68 gflg = 1; 69 return(gflg? (char **)NULL: wp); 70} 71 72/* 73 * Make the exported environment from the exported 74 * names in the dictionary. Keyword assignments 75 * will already have been done. 76 */ 77char ** 78makenv() 79 80{ 81 register struct wdblock *wb; 82 register struct var *vp; 83 84 wb = NULL; 85 for (vp = vlist; vp; vp = vp->next) 86 if (vp->status & EXPORT) 87 wb = addword(vp->name, wb); 88 wb = addword((char *)0, wb); 89 return(getwords(wb)); 90} 91 92char * 93evalstr(cp, f) 94register char *cp; 95int f; 96{ 97 struct wdblock *wb; 98 99 wb = NULL; 100 if (expand(cp, &wb, f)) { 101 if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL) 102 cp = ""; 103 DELETE(wb); 104 } else 105 cp = NULL; 106 return(cp); 107} 108 109static int 110expand(cp, wbp, f) 111register char *cp; 112register struct wdblock **wbp; 113int f; 114{ 115 jmp_buf ev; 116 117 gflg = 0; 118 if (cp == NULL) 119 return(0); 120 if (!anys("$`'\"", cp) && 121 !anys(ifs->value, cp) && 122 ((f&DOGLOB)==0 || !anys("[*?", cp))) { 123 cp = strsave(cp, areanum); 124 if (f & DOTRIM) 125 unquote(cp); 126 *wbp = addword(cp, *wbp); 127 return(1); 128 } 129 if (newenv(setjmp(errpt = ev)) == 0) { 130 PUSHIO(aword, cp, strchar); 131 e.iobase = e.iop; 132 while ((cp = blank(f)) && gflg == 0) { 133 e.linep = cp; 134 cp = strsave(cp, areanum); 135 if ((f&DOGLOB) == 0) { 136 if (f & DOTRIM) 137 unquote(cp); 138 *wbp = addword(cp, *wbp); 139 } else 140 *wbp = glob(cp, *wbp); 141 } 142 quitenv(); 143 } else 144 gflg = 1; 145 return(gflg == 0); 146} 147 148/* 149 * Blank interpretation and quoting 150 */ 151static char * 152blank(f) 153int f; 154{ 155 register c, c1; 156 register char *sp; 157 int scanequals, foundequals; 158 159 sp = e.linep; 160 scanequals = f & DOKEY; 161 foundequals = 0; 162 163loop: 164 switch (c = subgetc('"', foundequals)) { 165 case 0: 166 if (sp == e.linep) 167 return(0); 168 *e.linep++ = 0; 169 return(sp); 170 171 default: 172 if (f & DOBLANK && any(c, ifs->value)) 173 goto loop; 174 break; 175 176 case '"': 177 case '\'': 178 scanequals = 0; 179 if (INSUB()) 180 break; 181 for (c1 = c; (c = subgetc(c1, 1)) != c1;) { 182 if (c == 0) 183 break; 184 if (c == '\'' || !any(c, "$`\"")) 185 c |= QUOTE; 186 *e.linep++ = c; 187 } 188 c = 0; 189 } 190 unget(c); 191 if (!letter(c)) 192 scanequals = 0; 193 for (;;) { 194 c = subgetc('"', foundequals); 195 if (c == 0 || 196 f & (DOBLANK && any(c, ifs->value)) || 197 (!INSUB() && any(c, "\"'"))) { 198 scanequals = 0; 199 unget(c); 200 if (any(c, "\"'")) 201 goto loop; 202 break; 203 } 204 if (scanequals) 205 if (c == '=') { 206 foundequals = 1; 207 scanequals = 0; 208 } 209 else if (!letnum(c)) 210 scanequals = 0; 211 *e.linep++ = c; 212 } 213 *e.linep++ = 0; 214 return(sp); 215} 216 217/* 218 * Get characters, substituting for ` and $ 219 */ 220int 221subgetc(ec, quoted) 222register char ec; 223int quoted; 224{ 225 register char c; 226 227again: 228 c = getc(ec); 229 if (!INSUB() && ec != '\'') { 230 if (c == '`') { 231 if (grave(quoted) == 0) 232 return(0); 233 e.iop->task = XGRAVE; 234 goto again; 235 } 236 if (c == '$' && (c = dollar(quoted)) == 0) { 237 e.iop->task = XDOLL; 238 goto again; 239 } 240 } 241 return(c); 242} 243 244/* 245 * Prepare to generate the string returned by ${} substitution. 246 */ 247static int 248dollar(quoted) 249int quoted; 250{ 251 int otask; 252 struct io *oiop; 253 char *dolp; 254 register char *s, c, *cp; 255 struct var *vp; 256 257 c = readc(); 258 s = e.linep; 259 if (c != '{') { 260 *e.linep++ = c; 261 if (letter(c)) { 262 while ((c = readc())!=0 && letnum(c)) 263 if (e.linep < elinep) 264 *e.linep++ = c; 265 unget(c); 266 } 267 c = 0; 268 } else { 269 oiop = e.iop; 270 otask = e.iop->task; 271 e.iop->task = XOTHER; 272 while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n') 273 if (e.linep < elinep) 274 *e.linep++ = c; 275 if (oiop == e.iop) 276 e.iop->task = otask; 277 if (c != '}') { 278 err("unclosed ${"); 279 gflg++; 280 return(c); 281 } 282 } 283 if (e.linep >= elinep) { 284 err("string in ${} too long"); 285 gflg++; 286 e.linep -= 10; 287 } 288 *e.linep = 0; 289 if (*s) 290 for (cp = s+1; *cp; cp++) 291 if (any(*cp, "=-+?")) { 292 c = *cp; 293 *cp++ = 0; 294 break; 295 } 296 if (s[1] == 0 && (*s == '*' || *s == '@')) { 297 if (dolc > 1) { 298 /* currently this does not distinguish $* and $@ */ 299 /* should check dollar */ 300 e.linep = s; 301 PUSHIO(awordlist, dolv+1, dolchar); 302 return(0); 303 } else { /* trap the nasty ${=} */ 304 s[0] = '1'; 305 s[1] = 0; 306 } 307 } 308 vp = lookup(s); 309 if ((dolp = vp->value) == null) { 310 switch (c) { 311 case '=': 312 if (digit(*s)) { 313 err("cannot use ${...=...} with $n"); 314 gflg++; 315 break; 316 } 317 setval(vp, cp); 318 dolp = vp->value; 319 break; 320 321 case '-': 322 dolp = strsave(cp, areanum); 323 break; 324 325 case '?': 326 if (*cp == 0) { 327 prs("missing value for "); 328 err(s); 329 } else 330 err(cp); 331 gflg++; 332 break; 333 } 334 } else if (c == '+') 335 dolp = strsave(cp, areanum); 336 if (flag['u'] && dolp == null) { 337 prs("unset variable: "); 338 err(s); 339 gflg++; 340 } 341 e.linep = s; 342 PUSHIO(aword, dolp, quoted ? qstrchar : strchar); 343 return(0); 344} 345 346/* 347 * Run the command in `...` and read its output. 348 */ 349static int 350grave(quoted) 351int quoted; 352{ 353 register char *cp; 354 register int i; 355 int pf[2]; 356 357 for (cp = e.iop->argp->aword; *cp != '`'; cp++) 358 if (*cp == 0) { 359 err("no closing `"); 360 return(0); 361 } 362 if (openpipe(pf) < 0) 363 return(0); 364 if ((i = fork()) == -1) { 365 closepipe(pf); 366 err("try again"); 367 return(0); 368 } 369 if (i != 0) { 370 e.iop->argp->aword = ++cp; 371 close(pf[1]); 372 PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar); 373 return(1); 374 } 375 *cp = 0; 376 /* allow trapped signals */ 377 for (i=0; i<=_NSIG; i++) 378 if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN) 379 signal(i, SIG_DFL); 380 dup2(pf[1], 1); 381 closepipe(pf); 382 flag['e'] = 0; 383 flag['v'] = 0; 384 flag['n'] = 0; 385 cp = strsave(e.iop->argp->aword, 0); 386 areanum = 1; 387 freehere(areanum); 388 freearea(areanum); /* free old space */ 389 e.oenv = NULL; 390 e.iop = (e.iobase = iostack) - 1; 391 unquote(cp); 392 talking = 0; 393 PUSHIO(aword, cp, nlchar); 394 onecommand(); 395 exit(1); 396} 397 398char * 399unquote(as) 400register char *as; 401{ 402 register char *s; 403 404 if ((s = as) != NULL) 405 while (*s) 406 *s++ &= ~QUOTE; 407 return(as); 408} 409 410/* -------- glob.c -------- */ 411/* #include "sh.h" */ 412 413/* 414 * glob 415 */ 416 417#define scopy(x) strsave((x), areanum) 418#define BLKSIZ 512 419#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent)) 420 421static struct wdblock *cl, *nl; 422static char spcl[] = "[?*"; 423 424struct wdblock * 425glob(cp, wb) 426char *cp; 427struct wdblock *wb; 428{ 429 register i; 430 register char *pp; 431 432 if (cp == 0) 433 return(wb); 434 i = 0; 435 for (pp = cp; *pp; pp++) 436 if (any(*pp, spcl)) 437 i++; 438 else if (!any(*pp & ~QUOTE, spcl)) 439 *pp &= ~QUOTE; 440 if (i != 0) { 441 for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) { 442 nl = newword(cl->w_nword*2); 443 for(i=0; i<cl->w_nword; i++) { /* for each argument */ 444 for (pp = cl->w_words[i]; *pp; pp++) 445 if (any(*pp, spcl)) { 446 globname(cl->w_words[i], pp); 447 break; 448 } 449 if (*pp == '\0') 450 nl = addword(scopy(cl->w_words[i]), nl); 451 } 452 for(i=0; i<cl->w_nword; i++) 453 DELETE(cl->w_words[i]); 454 DELETE(cl); 455 } 456 for(i=0; i<cl->w_nword; i++) 457 unquote(cl->w_words[i]); 458 glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); 459 if (cl->w_nword) { 460 for (i=0; i<cl->w_nword; i++) 461 wb = addword(cl->w_words[i], wb); 462 DELETE(cl); 463 return(wb); 464 } 465 } 466 wb = addword(unquote(cp), wb); 467 return(wb); 468} 469 470void 471globname(we, pp) 472char *we; 473register char *pp; 474{ 475 register char *np, *cp; 476 char *name, *gp, *dp; 477 int dn, j, n, k; 478 DIR *dirp; 479 struct dirent *de; 480 char dname[NAME_MAX+1]; 481 struct stat dbuf; 482 483 for (np = we; np != pp; pp--) 484 if (pp[-1] == '/') 485 break; 486 for (dp = cp = space((int)(pp-np)+3); np < pp;) 487 *cp++ = *np++; 488 *cp++ = '.'; 489 *cp = '\0'; 490 for (gp = cp = space(strlen(pp)+1); *np && *np != '/';) 491 *cp++ = *np++; 492 *cp = '\0'; 493 dirp = opendir(dp); 494 if (dirp == 0) { 495 DELETE(dp); 496 DELETE(gp); 497 return; 498 } 499 dname[NAME_MAX] = '\0'; 500 while ((de=readdir(dirp))!=NULL) { 501 /* XXX Hmmm... What this could be? (abial) */ 502 /* 503 if (ent[j].d_ino == 0) 504 continue; 505 */ 506 strncpy(dname, de->d_name, NAME_MAX); 507 if (dname[0] == '.') 508 if (*gp != '.') 509 continue; 510 for(k=0; k<NAME_MAX; k++) 511 if (any(dname[k], spcl)) 512 dname[k] |= QUOTE; 513 if (gmatch(dname, gp)) { 514 name = generate(we, pp, dname, np); 515 if (*np && !anys(np, spcl)) { 516 if (stat(name,&dbuf)) { 517 DELETE(name); 518 continue; 519 } 520 } 521 nl = addword(name, nl); 522 } 523 } 524 closedir(dirp); 525 DELETE(dp); 526 DELETE(gp); 527} 528 529/* 530 * generate a pathname as below. 531 * start..end1 / middle end 532 * the slashes come for free 533 */ 534static char * 535generate(start1, end1, middle, end) 536char *start1; 537register char *end1; 538char *middle, *end; 539{ 540 char *p; 541 register char *op, *xp; 542 543 p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2); 544 for (xp = start1; xp != end1;) 545 *op++ = *xp++; 546 for (xp = middle; (*op++ = *xp++) != '\0';) 547 ; 548 op--; 549 for (xp = end; (*op++ = *xp++) != '\0';) 550 ; 551 return(p); 552} 553 554static int 555anyspcl(wb) 556register struct wdblock *wb; 557{ 558 register i; 559 register char **wd; 560 561 wd = wb->w_words; 562 for (i=0; i<wb->w_nword; i++) 563 if (anys(spcl, *wd++)) 564 return(1); 565 return(0); 566} 567 568static int 569xstrcmp(p1, p2) 570char *p1, *p2; 571{ 572 return(strcmp(*(char **)p1, *(char **)p2)); 573} 574 575/* -------- word.c -------- */ 576/* #include "sh.h" */ 577/* #include "word.h" */ 578 579#define NSTART 16 /* default number of words to allow for initially */ 580 581struct wdblock * 582newword(nw) 583register int nw; 584{ 585 register struct wdblock *wb; 586 587 wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *)); 588 wb->w_bsize = nw; 589 wb->w_nword = 0; 590 return(wb); 591} 592 593struct wdblock * 594addword(wd, wb) 595char *wd; 596register struct wdblock *wb; 597{ 598 register struct wdblock *wb2; 599 register nw; 600 601 if (wb == NULL) 602 wb = newword(NSTART); 603 if ((nw = wb->w_nword) >= wb->w_bsize) { 604 wb2 = newword(nw * 2); 605 memcopy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *)); 606 wb2->w_nword = nw; 607 DELETE(wb); 608 wb = wb2; 609 } 610 wb->w_words[wb->w_nword++] = wd; 611 return(wb); 612} 613 614char ** 615getwords(wb) 616register struct wdblock *wb; 617{ 618 register char **wd; 619 register nb; 620 621 if (wb == NULL) 622 return((char **)NULL); 623 if (wb->w_nword == 0) { 624 DELETE(wb); 625 return((char **)NULL); 626 } 627 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); 628 memcopy((char *)wd, (char *)wb->w_words, nb); 629 DELETE(wb); /* perhaps should done by caller */ 630 return(wd); 631} 632 633_PROTOTYPE(int (*func), (char *, char *)); 634int globv; 635 636void 637glob0(a0, a1, a2, a3) 638char *a0; 639unsigned a1; 640int a2; 641_PROTOTYPE(int (*a3), (char *, char *)); 642{ 643 func = a3; 644 globv = a2; 645 glob1(a0, a0 + a1 * a2); 646} 647 648void 649glob1(base, lim) 650char *base, *lim; 651{ 652 register char *i, *j; 653 int v2; 654 char *lptr, *hptr; 655 int c; 656 unsigned n; 657 658 659 v2 = globv; 660 661top: 662 if ((n=(int)(lim-base)) <= v2) 663 return; 664 n = v2 * (n / (2*v2)); 665 hptr = lptr = base+n; 666 i = base; 667 j = lim-v2; 668 for(;;) { 669 if (i < lptr) { 670 if ((c = (*func)(i, lptr)) == 0) { 671 glob2(i, lptr -= v2); 672 continue; 673 } 674 if (c < 0) { 675 i += v2; 676 continue; 677 } 678 } 679 680begin: 681 if (j > hptr) { 682 if ((c = (*func)(hptr, j)) == 0) { 683 glob2(hptr += v2, j); 684 goto begin; 685 } 686 if (c > 0) { 687 if (i == lptr) { 688 glob3(i, hptr += v2, j); 689 i = lptr += v2; 690 goto begin; 691 } 692 glob2(i, j); 693 j -= v2; 694 i += v2; 695 continue; 696 } 697 j -= v2; 698 goto begin; 699 } 700 701 702 if (i == lptr) { 703 if (lptr-base >= lim-hptr) { 704 glob1(hptr+v2, lim); 705 lim = lptr; 706 } else { 707 glob1(base, lptr); 708 base = hptr+v2; 709 } 710 goto top; 711 } 712 713 714 glob3(j, lptr -= v2, i); 715 j = hptr -= v2; 716 } 717} 718 719void 720glob2(i, j) 721char *i, *j; 722{ 723 register char *index1, *index2, c; 724 int m; 725 726 m = globv; 727 index1 = i; 728 index2 = j; 729 do { 730 c = *index1; 731 *index1++ = *index2; 732 *index2++ = c; 733 } while(--m); 734} 735 736void 737glob3(i, j, k) 738char *i, *j, *k; 739{ 740 register char *index1, *index2, *index3; 741 int c; 742 int m; 743 744 m = globv; 745 index1 = i; 746 index2 = j; 747 index3 = k; 748 do { 749 c = *index1; 750 *index1++ = *index3; 751 *index3++ = *index2; 752 *index2++ = c; 753 } while(--m); 754} 755 756char * 757memcopy(ato, from, nb) 758register char *ato, *from; 759register int nb; 760{ 761 register char *to; 762 763 to = ato; 764 while (--nb >= 0) 765 *to++ = *from++; 766 return(ato); 767} 768