1 0 stevel /* 2 356 muffin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 0 stevel * Use is subject to license terms. 4 0 stevel */ 5 0 stevel 6 0 stevel /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 0 stevel /* All Rights Reserved */ 8 0 stevel 9 0 stevel /* 10 0 stevel * Copyright (c) 1980 Regents of the University of California. 11 0 stevel * All rights reserved. The Berkeley Software License Agreement 12 0 stevel * specifies the terms and conditions for redistribution. 13 0 stevel */ 14 0 stevel 15 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 16 0 stevel 17 0 stevel #include "sh.h" 18 0 stevel #include "sh.tconst.h" 19 0 stevel #include <dirent.h> 20 356 muffin #include <strings.h> 21 0 stevel #ifdef MBCHAR 22 0 stevel #include <widec.h> /* wcsetno() */ 23 0 stevel #include <fnmatch.h> /* fnmatch() */ 24 0 stevel #endif /* MBCHAR */ 25 0 stevel 26 0 stevel /* 27 0 stevel * C Shell 28 0 stevel */ 29 0 stevel 30 0 stevel int globcnt; 31 0 stevel 32 0 stevel tchar *gpath, *gpathp, *lastgpathp; 33 0 stevel int globbed; 34 0 stevel bool noglob; 35 0 stevel bool nonomatch; 36 0 stevel tchar *entp; 37 0 stevel tchar **sortbas; 38 356 muffin int sortscmp(tchar **, tchar **); 39 356 muffin void ginit(tchar **); 40 356 muffin void collect(tchar *); 41 356 muffin void acollect(tchar *); 42 356 muffin void expand(tchar *); 43 356 muffin void matchdir_(tchar *); 44 356 muffin void Gcat(tchar *, tchar *); 45 356 muffin void addpath(tchar); 46 356 muffin void tglob(tchar **); 47 356 muffin tchar **dobackp(tchar *, bool); 48 356 muffin void backeval(tchar *, bool); 49 356 muffin void psave(tchar); 50 356 muffin void pword(void); 51 356 muffin 52 356 muffin extern DIR *opendir_(tchar *); 53 0 stevel 54 0 stevel #define sort() qsort((char *)sortbas, &gargv[gargc] - sortbas, \ 55 0 stevel sizeof (*sortbas), (int (*)(const void *, \ 56 0 stevel const void *)) sortscmp), sortbas = &gargv[gargc] 57 0 stevel 58 0 stevel 59 0 stevel tchar ** 60 356 muffin glob(tchar **v) 61 0 stevel { 62 0 stevel tchar agpath[BUFSIZ]; 63 0 stevel tchar *agargv[GAVSIZ]; 64 0 stevel 65 0 stevel gpath = agpath; gpathp = gpath; *gpathp = 0; 66 0 stevel lastgpathp = &gpath[BUFSIZ - 2]; 67 0 stevel ginit(agargv); globcnt = 0; 68 0 stevel #ifdef TRACE 69 0 stevel tprintf("TRACE- glob()\n"); 70 0 stevel #endif 71 0 stevel #ifdef GDEBUG 72 0 stevel printf("glob entered: "); blkpr(v); printf("\n"); 73 0 stevel #endif 74 0 stevel noglob = adrof(S_noglob /* "noglob" */) != 0; 75 0 stevel nonomatch = adrof(S_nonomatch /* "nonomatch" */) != 0; 76 0 stevel globcnt = noglob | nonomatch; 77 0 stevel while (*v) 78 0 stevel collect(*v++); 79 0 stevel #ifdef GDEBUG 80 0 stevel printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); 81 0 stevel blkpr(gargv); printf("\n"); 82 0 stevel #endif 83 0 stevel if (globcnt == 0 && (gflag&1)) { 84 0 stevel blkfree(gargv), gargv = 0; 85 0 stevel return (0); 86 0 stevel } else 87 0 stevel return (gargv = copyblk(gargv)); 88 0 stevel } 89 0 stevel 90 356 muffin void 91 356 muffin ginit(tchar **agargv) 92 0 stevel { 93 0 stevel 94 0 stevel agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; 95 0 stevel gnleft = NCARGS - 4; 96 0 stevel } 97 0 stevel 98 356 muffin void 99 356 muffin collect(tchar *as) 100 0 stevel { 101 356 muffin int i; 102 0 stevel 103 0 stevel #ifdef TRACE 104 0 stevel tprintf("TRACE- collect()\n"); 105 0 stevel #endif 106 0 stevel if (any('`', as)) { 107 0 stevel #ifdef GDEBUG 108 0 stevel printf("doing backp of %t\n", as); 109 0 stevel #endif 110 0 stevel (void) dobackp(as, 0); 111 0 stevel #ifdef GDEBUG 112 0 stevel printf("backp done, acollect'ing\n"); 113 0 stevel #endif 114 0 stevel /* 115 0 stevel * dobackp has the side effect of messing with 116 0 stevel * gflag, since it does more globbing, so check 117 0 stevel * if the results is still globbable 118 559 nakanon */ 119 0 stevel tglob(pargv); 120 0 stevel 121 0 stevel for (i = 0; i < pargc; i++) 122 0 stevel if (noglob) { 123 0 stevel Gcat(pargv[i], S_ /* "" */); 124 0 stevel sortbas = &gargv[gargc]; 125 0 stevel } else 126 0 stevel acollect(pargv[i]); 127 0 stevel if (pargv) 128 0 stevel blkfree(pargv), pargv = 0; 129 0 stevel #ifdef GDEBUG 130 0 stevel printf("acollect done\n"); 131 0 stevel #endif 132 0 stevel } else if (noglob || eq(as, S_LBRA /* "{" */) || 133 0 stevel eq(as, S_BRABRA /* "{}" */)) { 134 0 stevel Gcat(as, S_ /* "" */); 135 0 stevel sort(); 136 0 stevel } else 137 0 stevel acollect(as); 138 0 stevel } 139 0 stevel 140 356 muffin void 141 356 muffin acollect(tchar *as) 142 0 stevel { 143 356 muffin long ogargc = gargc; 144 0 stevel 145 0 stevel #ifdef TRACE 146 0 stevel tprintf("TRACE- acollect()\n"); 147 0 stevel #endif 148 0 stevel gpathp = gpath; *gpathp = 0; globbed = 0; 149 0 stevel expand(as); 150 0 stevel if (gargc == ogargc) { 151 0 stevel if (nonomatch) { 152 0 stevel Gcat(as, S_ /* "" */); 153 0 stevel sort(); 154 0 stevel } 155 0 stevel } else 156 0 stevel sort(); 157 0 stevel } 158 0 stevel 159 0 stevel /* 160 0 stevel * String compare for qsort. Also used by filec code in sh.file.c. 161 0 stevel */ 162 356 muffin int 163 356 muffin sortscmp(tchar **a1, tchar **a2) 164 0 stevel { 165 0 stevel 166 0 stevel return (strcoll_(*a1, *a2)); 167 0 stevel } 168 0 stevel 169 356 muffin void 170 356 muffin expand(tchar *as) 171 0 stevel { 172 356 muffin tchar *cs; 173 356 muffin tchar *sgpathp, *oldcs; 174 0 stevel struct stat stb; 175 0 stevel 176 0 stevel #ifdef TRACE 177 0 stevel tprintf("TRACE- expand()\n"); 178 0 stevel #endif 179 0 stevel sgpathp = gpathp; 180 0 stevel cs = as; 181 0 stevel if (*cs == '~' && gpathp == gpath) { 182 0 stevel addpath('~'); 183 0 stevel for (cs++; alnum(*cs) || *cs == '-'; ) 184 0 stevel addpath(*cs++); 185 0 stevel if (!*cs || *cs == '/') { 186 0 stevel if (gpathp != gpath + 1) { 187 0 stevel *gpathp = 0; 188 0 stevel if (gethdir(gpath + 1)) 189 0 stevel /* 190 0 stevel * modified from %s to %t 191 0 stevel */ 192 0 stevel error("Unknown user: %t", gpath + 1); 193 0 stevel (void) strcpy_(gpath, gpath + 1); 194 0 stevel } else 195 0 stevel (void) strcpy_(gpath, 196 0 stevel value(S_home /* "home" */)); 197 0 stevel gpathp = strend(gpath); 198 0 stevel } 199 0 stevel } 200 0 stevel while (!isglob(*cs)) { 201 0 stevel if (*cs == 0) { 202 0 stevel if (!globbed) 203 0 stevel Gcat(gpath, S_ /* "" */); 204 0 stevel else if (lstat_(gpath, &stb) >= 0) { 205 0 stevel Gcat(gpath, S_ /* "" */); 206 0 stevel globcnt++; 207 0 stevel } 208 0 stevel goto endit; 209 0 stevel } 210 0 stevel addpath(*cs++); 211 0 stevel } 212 0 stevel oldcs = cs; 213 0 stevel while (cs > as && *cs != '/') 214 0 stevel cs--, gpathp--; 215 0 stevel if (*cs == '/') 216 0 stevel cs++, gpathp++; 217 0 stevel *gpathp = 0; 218 0 stevel if (*oldcs == '{') { 219 0 stevel (void) execbrc(cs, NOSTR); 220 0 stevel return; 221 0 stevel } 222 0 stevel matchdir_(cs); 223 0 stevel endit: 224 0 stevel gpathp = sgpathp; 225 0 stevel *gpathp = 0; 226 0 stevel } 227 0 stevel 228 356 muffin void 229 356 muffin matchdir_(tchar *pattern) 230 0 stevel { 231 0 stevel struct stat stb; 232 356 muffin struct dirent *dp; 233 356 muffin DIR *dirp; 234 0 stevel tchar curdir_[MAXNAMLEN+1]; 235 0 stevel int slproc = 0; 236 0 stevel 237 0 stevel #ifdef TRACE 238 0 stevel tprintf("TRACE- matchdir()\n"); 239 0 stevel #endif 240 0 stevel /* 241 0 stevel * BSD's opendir would open "." if argument is NULL, but not S5 242 559 nakanon */ 243 0 stevel 244 0 stevel if (*gpath == NULL) 245 0 stevel dirp = opendir_(S_DOT /* "." */); 246 0 stevel else 247 0 stevel dirp = opendir_(gpath); 248 0 stevel if (dirp == NULL) { 249 0 stevel if (globbed) 250 0 stevel return; 251 0 stevel goto patherr2; 252 0 stevel } 253 0 stevel if (fstat(dirp->dd_fd, &stb) < 0) 254 0 stevel goto patherr1; 255 0 stevel if (!isdir(stb)) { 256 0 stevel errno = ENOTDIR; 257 0 stevel goto patherr1; 258 0 stevel } 259 0 stevel while ((dp = readdir(dirp)) != NULL) { 260 0 stevel 261 0 stevel if (dp->d_ino == 0) 262 0 stevel continue; 263 0 stevel strtots(curdir_, dp->d_name); 264 0 stevel slproc = 0; 265 0 stevel if (match(curdir_, pattern, &slproc)) { 266 0 stevel Gcat(gpath, curdir_); 267 0 stevel globcnt++; 268 0 stevel } 269 0 stevel } 270 0 stevel unsetfd(dirp->dd_fd); 271 0 stevel closedir_(dirp); 272 0 stevel return; 273 0 stevel 274 0 stevel patherr1: 275 0 stevel unsetfd(dirp->dd_fd); 276 0 stevel closedir_(dirp); 277 0 stevel patherr2: 278 0 stevel Perror(gpath); 279 0 stevel } 280 0 stevel 281 356 muffin int 282 356 muffin execbrc(tchar *p, tchar *s) 283 0 stevel { 284 0 stevel tchar restbuf[BUFSIZ + 2]; 285 356 muffin tchar *pe, *pm, *pl; 286 0 stevel int brclev = 0; 287 0 stevel tchar *lm, savec, *sgpathp; 288 0 stevel int slproc = 0; 289 0 stevel 290 0 stevel #ifdef TRACE 291 0 stevel tprintf("TRACE- execbrc()\n"); 292 0 stevel #endif 293 0 stevel for (lm = restbuf; *p != '{'; *lm++ = *p++) 294 0 stevel continue; 295 0 stevel for (pe = ++p; *pe; pe++) 296 0 stevel switch (*pe) { 297 0 stevel 298 0 stevel case '{': 299 0 stevel brclev++; 300 0 stevel continue; 301 0 stevel 302 0 stevel case '}': 303 0 stevel if (brclev == 0) 304 0 stevel goto pend; 305 0 stevel brclev--; 306 0 stevel continue; 307 0 stevel 308 0 stevel case '[': 309 0 stevel for (pe++; *pe && *pe != ']'; pe++) 310 0 stevel continue; 311 0 stevel if (!*pe) 312 0 stevel error("Missing ]"); 313 0 stevel continue; 314 0 stevel } 315 0 stevel pend: 316 0 stevel if (brclev || !*pe) 317 0 stevel error("Missing }"); 318 0 stevel for (pl = pm = p; pm <= pe; pm++) 319 0 stevel switch (*pm & (QUOTE|TRIM)) { 320 0 stevel 321 0 stevel case '{': 322 0 stevel brclev++; 323 0 stevel continue; 324 0 stevel 325 0 stevel case '}': 326 0 stevel if (brclev) { 327 0 stevel brclev--; 328 0 stevel continue; 329 0 stevel } 330 0 stevel goto doit; 331 0 stevel 332 0 stevel case ',': 333 0 stevel if (brclev) 334 0 stevel continue; 335 0 stevel doit: 336 0 stevel savec = *pm; 337 0 stevel *pm = 0; 338 0 stevel (void) strcpy_(lm, pl); 339 0 stevel (void) strcat_(restbuf, pe + 1); 340 0 stevel *pm = savec; 341 0 stevel if (s == 0) { 342 0 stevel sgpathp = gpathp; 343 0 stevel expand(restbuf); 344 0 stevel gpathp = sgpathp; 345 0 stevel *gpathp = 0; 346 0 stevel } else if (amatch(s, restbuf, &slproc)) 347 0 stevel return (1); 348 0 stevel sort(); 349 0 stevel pl = pm + 1; 350 0 stevel continue; 351 0 stevel 352 0 stevel case '[': 353 0 stevel for (pm++; *pm && *pm != ']'; pm++) 354 0 stevel continue; 355 0 stevel if (!*pm) 356 0 stevel error("Missing ]"); 357 0 stevel continue; 358 0 stevel } 359 0 stevel return (0); 360 0 stevel } 361 0 stevel 362 356 muffin int 363 356 muffin match(tchar *s, tchar *p, int *slproc) 364 0 stevel { 365 356 muffin int c; 366 356 muffin tchar *sentp; 367 0 stevel tchar sglobbed = globbed; 368 0 stevel 369 0 stevel #ifdef TRACE 370 0 stevel tprintf("TRACE- match()\n"); 371 0 stevel #endif 372 0 stevel if (*s == '.' && *p != '.') 373 0 stevel return (0); 374 0 stevel sentp = entp; 375 0 stevel entp = s; 376 0 stevel c = amatch(s, p, slproc); 377 0 stevel entp = sentp; 378 0 stevel globbed = sglobbed; 379 0 stevel return (c); 380 0 stevel } 381 0 stevel 382 356 muffin int 383 356 muffin amatch(tchar *s, tchar *p, int *slproc) 384 0 stevel { 385 356 muffin int scc; 386 0 stevel int ok, lc; 387 0 stevel tchar *sgpathp; 388 0 stevel struct stat stb; 389 0 stevel int c, cc; 390 0 stevel 391 0 stevel #ifdef TRACE 392 0 stevel tprintf("TRACE- amatch()\n"); 393 0 stevel #endif 394 0 stevel globbed = 1; 395 0 stevel for (;;) { 396 0 stevel scc = *s++ & TRIM; 397 0 stevel switch (c = *p++) { 398 0 stevel 399 0 stevel case '{': 400 0 stevel return (execbrc(p - 1, s - 1)); 401 0 stevel 402 0 stevel case '[': 403 0 stevel ok = 0; 404 0 stevel lc = TRIM; 405 0 stevel while (cc = *p++) { 406 0 stevel if (cc == ']') { 407 0 stevel if (ok) 408 0 stevel break; 409 0 stevel return (0); 410 0 stevel } 411 0 stevel if (cc == '-') { 412 0 stevel #ifdef MBCHAR 413 0 stevel wchar_t rc = *p++; 414 0 stevel if (rc == ']') { 415 0 stevel p--; 416 0 stevel continue; 417 0 stevel } 418 0 stevel /* 419 0 stevel * Both ends of the char range 420 0 stevel * must belong to the same codeset. 421 0 stevel */ 422 0 stevel if (sh_bracket_exp(scc, lc, rc)) 423 0 stevel ok++; 424 0 stevel #else /* !MBCHAR */ 425 559 nakanon if (lc <= scc && scc <= (int)*p++) 426 0 stevel ok++; 427 0 stevel #endif /* !MBCHAR */ 428 0 stevel } else 429 0 stevel if (scc == (lc = cc)) 430 0 stevel ok++; 431 0 stevel } 432 0 stevel if (cc == 0) 433 0 stevel error("Missing ]"); 434 0 stevel continue; 435 0 stevel 436 0 stevel case '*': 437 0 stevel if (!*p) 438 0 stevel return (1); 439 0 stevel if (*p == '/') { 440 0 stevel p++; 441 0 stevel goto slash; 442 0 stevel } else if (*p == '*') { 443 0 stevel s--; 444 0 stevel continue; 445 0 stevel } 446 0 stevel 447 0 stevel for (s--; *s; s++) 448 0 stevel if (amatch(s, p, slproc)) 449 0 stevel return (1); 450 0 stevel 451 0 stevel return (0); 452 0 stevel 453 0 stevel case 0: 454 0 stevel return (scc == 0); 455 0 stevel 456 0 stevel default: 457 0 stevel if ((c & TRIM) != scc) 458 0 stevel return (0); 459 0 stevel continue; 460 0 stevel 461 0 stevel case '?': 462 0 stevel if (scc == 0) 463 0 stevel return (0); 464 0 stevel continue; 465 0 stevel 466 0 stevel case '/': 467 0 stevel if (scc) 468 0 stevel return (0); 469 0 stevel slash: 470 0 stevel if (*slproc) /* Need to expand "/" only once */ 471 0 stevel return (0); 472 0 stevel else 473 0 stevel *slproc = 1; 474 0 stevel 475 0 stevel s = entp; 476 0 stevel sgpathp = gpathp; 477 0 stevel while (*s) 478 0 stevel addpath(*s++); 479 0 stevel addpath('/'); 480 0 stevel if (stat_(gpath, &stb) == 0 && isdir(stb)) 481 0 stevel if (*p == 0) { 482 0 stevel Gcat(gpath, S_ /* "" */); 483 0 stevel globcnt++; 484 0 stevel } else 485 0 stevel expand(p); 486 0 stevel gpathp = sgpathp; 487 0 stevel *gpathp = 0; 488 0 stevel return (0); 489 0 stevel } 490 0 stevel } 491 0 stevel } 492 0 stevel 493 356 muffin int 494 356 muffin Gmatch(tchar *s, tchar *p) 495 0 stevel { 496 356 muffin int scc; 497 0 stevel int ok, lc; 498 0 stevel int c, cc; 499 0 stevel 500 0 stevel #ifdef TRACE 501 0 stevel tprintf("TRACE- Gmatch()\n"); 502 0 stevel #endif 503 0 stevel for (;;) { 504 0 stevel scc = *s++ & TRIM; 505 0 stevel switch (c = *p++) { 506 0 stevel 507 0 stevel case '[': 508 0 stevel ok = 0; 509 0 stevel lc = TRIM; 510 0 stevel while (cc = *p++) { 511 0 stevel if (cc == ']') { 512 0 stevel if (ok) 513 0 stevel break; 514 0 stevel return (0); 515 0 stevel } 516 0 stevel if (cc == '-') { 517 0 stevel #ifdef MBCHAR 518 0 stevel wchar_t rc = *p++; 519 0 stevel /* 520 0 stevel * Both ends of the char range 521 0 stevel * must belong to the same codeset... 522 0 stevel */ 523 0 stevel if (sh_bracket_exp(scc, lc, rc)) 524 0 stevel ok++; 525 0 stevel #else /* !MBCHAR */ 526 559 nakanon if (lc <= scc && scc <= (int)*p++) 527 0 stevel ok++; 528 0 stevel #endif /* !MBCHAR */ 529 0 stevel } else 530 0 stevel if (scc == (lc = cc)) 531 0 stevel ok++; 532 0 stevel } 533 0 stevel if (cc == 0) 534 0 stevel bferr("Missing ]"); 535 0 stevel continue; 536 0 stevel 537 0 stevel case '*': 538 0 stevel if (!*p) 539 0 stevel return (1); 540 0 stevel for (s--; *s; s++) 541 0 stevel if (Gmatch(s, p)) 542 0 stevel return (1); 543 0 stevel return (0); 544 0 stevel 545 0 stevel case 0: 546 0 stevel return (scc == 0); 547 0 stevel 548 0 stevel default: 549 0 stevel if ((c & TRIM) != scc) 550 0 stevel return (0); 551 0 stevel continue; 552 0 stevel 553 0 stevel case '?': 554 0 stevel if (scc == 0) 555 0 stevel return (0); 556 0 stevel continue; 557 0 stevel 558 0 stevel } 559 0 stevel } 560 0 stevel } 561 0 stevel 562 356 muffin void 563 356 muffin Gcat(tchar *s1, tchar *s2) 564 0 stevel { 565 356 muffin tchar *p, *q; 566 0 stevel int n; 567 0 stevel 568 0 stevel #ifdef TRACE 569 0 stevel tprintf("TRACE- Gcat()\n"); 570 0 stevel #endif 571 0 stevel for (p = s1; *p++; ) 572 0 stevel ; 573 0 stevel for (q = s2; *q++; ) 574 0 stevel ; 575 0 stevel gnleft -= (n = (p - s1) + (q - s2) - 1); 576 0 stevel if (gnleft <= 0 || ++gargc >= GAVSIZ) 577 0 stevel error("Arguments too long"); 578 0 stevel gargv[gargc] = 0; 579 0 stevel p = gargv[gargc - 1] = (tchar *) xalloc((unsigned)n*sizeof (tchar)); 580 0 stevel 581 0 stevel for (q = s1; *p++ = *q++; ) 582 0 stevel ; 583 0 stevel for (p--, q = s2; *p++ = *q++; ) 584 0 stevel ; 585 0 stevel } 586 0 stevel 587 356 muffin void 588 356 muffin addpath(tchar c) 589 0 stevel { 590 0 stevel 591 0 stevel #ifdef TRACE 592 0 stevel tprintf("TRACE- addpath()\n"); 593 0 stevel #endif 594 0 stevel if (gpathp >= lastgpathp) 595 0 stevel error("Pathname too long"); 596 0 stevel *gpathp++ = c & TRIM; 597 0 stevel *gpathp = 0; 598 0 stevel } 599 0 stevel 600 356 muffin void 601 356 muffin rscan(tchar **t, int (*f)(int)) 602 0 stevel { 603 356 muffin tchar *p; 604 0 stevel 605 0 stevel #ifdef TRACE 606 0 stevel tprintf("TRACE- rscan()\n"); 607 0 stevel #endif 608 0 stevel while (p = *t++) 609 0 stevel while (*p) 610 0 stevel (*f)(*p++); 611 0 stevel } 612 0 stevel 613 356 muffin void 614 356 muffin trim(tchar **t) 615 0 stevel { 616 356 muffin tchar *p; 617 0 stevel 618 0 stevel #ifdef TRACE 619 0 stevel tprintf("TRACE- trim()\n"); 620 0 stevel #endif 621 0 stevel while (p = *t++) 622 0 stevel while (*p) 623 0 stevel *p++ &= TRIM; 624 0 stevel } 625 0 stevel 626 356 muffin void 627 356 muffin tglob(tchar **t) 628 0 stevel { 629 356 muffin tchar *p, c; 630 0 stevel 631 0 stevel #ifdef TRACE 632 0 stevel tprintf("TRACE- tglob()\n"); 633 0 stevel #endif 634 0 stevel while (p = *t++) { 635 0 stevel if (*p == '~') 636 0 stevel gflag |= 2; 637 0 stevel else if (*p == '{' && (p[1] == '\0' || 638 0 stevel p[1] == '}' && p[2] == '\0')) 639 0 stevel continue; 640 0 stevel while (c = *p++) 641 0 stevel if (isglob(c)) 642 0 stevel gflag |= c == '{' ? 2 : 1; 643 0 stevel } 644 0 stevel } 645 0 stevel 646 0 stevel tchar * 647 356 muffin globone(tchar *str) 648 0 stevel { 649 0 stevel tchar *gv[2]; 650 356 muffin tchar **gvp; 651 356 muffin tchar *cp; 652 0 stevel 653 0 stevel #ifdef TRACE 654 0 stevel tprintf("TRACE- globone()\n"); 655 0 stevel #endif 656 0 stevel gv[0] = str; 657 0 stevel gv[1] = 0; 658 0 stevel gflag = 0; 659 0 stevel tglob(gv); 660 0 stevel if (gflag) { 661 0 stevel gvp = glob(gv); 662 0 stevel if (gvp == 0) { 663 0 stevel setname(str); 664 0 stevel bferr("No match"); 665 0 stevel } 666 0 stevel cp = *gvp++; 667 0 stevel if (cp == 0) 668 0 stevel cp = S_ /* "" */; 669 0 stevel else if (*gvp) { 670 0 stevel setname(str); 671 0 stevel bferr("Ambiguous"); 672 0 stevel } else 673 0 stevel cp = strip(cp); 674 559 nakanon #if 0 675 0 stevel if (cp == 0 || *gvp) { 676 0 stevel setname(str); 677 0 stevel bferr(cp ? "Ambiguous" : "No output"); 678 0 stevel } 679 559 nakanon #endif 680 0 stevel xfree((char *)gargv); gargv = 0; 681 0 stevel } else { 682 0 stevel trim(gv); 683 0 stevel cp = savestr(gv[0]); 684 0 stevel } 685 0 stevel return (cp); 686 0 stevel } 687 0 stevel 688 0 stevel /* 689 0 stevel * Command substitute cp. If literal, then this is 690 0 stevel * a substitution from a << redirection, and so we should 691 0 stevel * not crunch blanks and tabs, separating words only at newlines. 692 0 stevel */ 693 0 stevel tchar ** 694 356 muffin dobackp(tchar *cp, bool literal) 695 0 stevel { 696 356 muffin tchar *lp, *rp; 697 0 stevel tchar *ep; 698 0 stevel tchar word[BUFSIZ]; 699 0 stevel tchar *apargv[GAVSIZ + 2]; 700 0 stevel 701 0 stevel #ifdef TRACE 702 0 stevel tprintf("TRACE- dobackp()\n"); 703 0 stevel #endif 704 0 stevel if (pargv) { 705 0 stevel blkfree(pargv); 706 0 stevel } 707 0 stevel pargv = apargv; 708 0 stevel pargv[0] = NOSTR; 709 0 stevel pargcp = pargs = word; 710 0 stevel pargc = 0; 711 0 stevel pnleft = BUFSIZ - 4; 712 0 stevel for (;;) { 713 0 stevel for (lp = cp; *lp != '`'; lp++) { 714 0 stevel if (*lp == 0) { 715 0 stevel if (pargcp != pargs) 716 0 stevel pword(); 717 0 stevel #ifdef GDEBUG 718 0 stevel printf("leaving dobackp\n"); 719 0 stevel #endif 720 0 stevel return (pargv = copyblk(pargv)); 721 0 stevel } 722 0 stevel psave(*lp); 723 0 stevel } 724 0 stevel lp++; 725 0 stevel for (rp = lp; *rp && *rp != '`'; rp++) 726 0 stevel if (*rp == '\\') { 727 0 stevel rp++; 728 0 stevel if (!*rp) 729 0 stevel goto oops; 730 0 stevel } 731 0 stevel if (!*rp) 732 0 stevel oops: 733 0 stevel error("Unmatched `"); 734 0 stevel ep = savestr(lp); 735 0 stevel ep[rp - lp] = 0; 736 0 stevel backeval(ep, literal); 737 0 stevel #ifdef GDEBUG 738 0 stevel printf("back from backeval\n"); 739 0 stevel #endif 740 0 stevel cp = rp + 1; 741 0 stevel } 742 0 stevel } 743 0 stevel 744 356 muffin void 745 356 muffin backeval(tchar *cp, bool literal) 746 0 stevel { 747 0 stevel int pvec[2]; 748 0 stevel int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 749 559 nakanon tchar ibuf[BUFSIZ + MB_LEN_MAX]; /* read_ can return extra bytes */ 750 356 muffin int icnt = 0, c; 751 356 muffin tchar *ip; 752 0 stevel bool hadnl = 0; 753 0 stevel tchar *fakecom[2]; 754 0 stevel struct command faket; 755 0 stevel 756 0 stevel #ifdef TRACE 757 0 stevel tprintf("TRACE- backeval()\n"); 758 0 stevel #endif 759 0 stevel faket.t_dtyp = TCOM; 760 0 stevel faket.t_dflg = 0; 761 0 stevel faket.t_dlef = 0; 762 0 stevel faket.t_drit = 0; 763 0 stevel faket.t_dspr = 0; 764 0 stevel faket.t_dcom = fakecom; 765 0 stevel fakecom[0] = S_QPPPQ; /* "` ... `" */; 766 0 stevel fakecom[1] = 0; 767 0 stevel /* 768 0 stevel * We do the psave job to temporarily change the current job 769 0 stevel * so that the following fork is considered a separate job. 770 0 stevel * This is so that when backquotes are used in a 771 0 stevel * builtin function that calls glob the "current job" is not corrupted. 772 0 stevel * We only need one level of pushed jobs as long as we are sure to 773 0 stevel * fork here. 774 0 stevel */ 775 0 stevel psavejob(); 776 0 stevel /* 777 0 stevel * It would be nicer if we could integrate this redirection more 778 0 stevel * with the routines in sh.sem.c by doing a fake execute on a builtin 779 0 stevel * function that was piped out. 780 0 stevel */ 781 0 stevel mypipe(pvec); 782 0 stevel if (pfork(&faket, -1) == 0) { 783 0 stevel struct wordent paraml; 784 0 stevel struct command *t; 785 0 stevel tchar oHIST; 786 0 stevel 787 0 stevel new_process(); 788 0 stevel (void) close(pvec[0]); 789 0 stevel unsetfd(pvec[0]); 790 0 stevel (void) dmove(pvec[1], 1); 791 0 stevel (void) dmove(SHDIAG, 2); 792 0 stevel reinitdesc(0, NULL); 793 0 stevel arginp = cp; 794 0 stevel while (*cp) 795 0 stevel *cp++ &= TRIM; 796 0 stevel /* 797 0 stevel * disable history subsitution in sub-shell 798 0 stevel * of `` evaluation prevents possible 799 0 stevel * infinite recursion of `` evaluation 800 0 stevel */ 801 0 stevel oHIST = HIST; 802 0 stevel HIST = 0; 803 0 stevel (void) lex(¶ml); 804 0 stevel HIST = oHIST; 805 0 stevel if (err) 806 0 stevel error("%s", gettext(err)); 807 0 stevel alias(¶ml); 808 0 stevel t = syntax(paraml.next, ¶ml, 0); 809 0 stevel if (err) 810 0 stevel error("%s", gettext(err)); 811 0 stevel if (t) 812 0 stevel t->t_dflg |= FPAR; 813 0 stevel (void) signal(SIGTSTP, SIG_IGN); 814 0 stevel (void) signal(SIGTTIN, SIG_IGN); 815 0 stevel (void) signal(SIGTTOU, SIG_IGN); 816 0 stevel execute(t, -1); 817 0 stevel exitstat(); 818 0 stevel } 819 0 stevel xfree(cp); 820 0 stevel (void) close(pvec[1]); 821 0 stevel unsetfd(pvec[1]); 822 0 stevel do { 823 0 stevel int cnt = 0; 824 0 stevel for (;;) { 825 0 stevel if (icnt == 0) { 826 0 stevel ip = ibuf; 827 0 stevel icnt = read_(pvec[0], ip, BUFSIZ); 828 0 stevel if (icnt <= 0) { 829 0 stevel c = -1; 830 0 stevel break; 831 0 stevel } 832 0 stevel } 833 0 stevel if (hadnl) 834 0 stevel break; 835 0 stevel --icnt; 836 0 stevel c = (*ip++ & TRIM); 837 0 stevel if (c == 0) 838 0 stevel break; 839 0 stevel if (c == '\n') { 840 0 stevel /* 841 0 stevel * Continue around the loop one 842 0 stevel * more time, so that we can eat 843 0 stevel * the last newline without terminating 844 0 stevel * this word. 845 0 stevel */ 846 0 stevel hadnl = 1; 847 0 stevel continue; 848 0 stevel } 849 0 stevel if (!quoted && issp(c)) 850 0 stevel break; 851 0 stevel cnt++; 852 0 stevel psave(c | quoted); 853 0 stevel } 854 0 stevel /* 855 0 stevel * Unless at end-of-file, we will form a new word 856 0 stevel * here if there were characters in the word, or in 857 0 stevel * any case when we take text literally. If 858 0 stevel * we didn't make empty words here when literal was 859 0 stevel * set then we would lose blank lines. 860 0 stevel */ 861 0 stevel if (c != -1 && (cnt || literal)) { 862 0 stevel if (pargc == GAVSIZ) 863 0 stevel break; 864 0 stevel pword(); 865 0 stevel } 866 0 stevel hadnl = 0; 867 0 stevel } while (c >= 0); 868 0 stevel #ifdef GDEBUG 869 0 stevel printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]); 870 0 stevel printf("also c = %c <%o>\n", (tchar) c, (tchar) c); 871 0 stevel #endif 872 0 stevel (void) close(pvec[0]); 873 0 stevel unsetfd(pvec[0]); 874 0 stevel pwait(); 875 0 stevel prestjob(); 876 0 stevel } 877 0 stevel 878 356 muffin void 879 356 muffin psave(tchar c) 880 0 stevel { 881 0 stevel #ifdef TRACE 882 0 stevel tprintf("TRACE- psave()\n"); 883 0 stevel #endif 884 0 stevel 885 0 stevel if (--pnleft <= 0) 886 0 stevel error("Word too long"); 887 0 stevel *pargcp++ = c; 888 0 stevel } 889 0 stevel 890 356 muffin void 891 356 muffin pword(void) 892 0 stevel { 893 0 stevel #ifdef TRACE 894 0 stevel tprintf("TRACE- pword()\n"); 895 0 stevel #endif 896 0 stevel 897 0 stevel psave(0); 898 0 stevel if (pargc == GAVSIZ) 899 0 stevel error("Too many words from ``"); 900 0 stevel pargv[pargc++] = savestr(pargs); 901 0 stevel pargv[pargc] = NOSTR; 902 0 stevel #ifdef GDEBUG 903 0 stevel printf("got word %t\n", pargv[pargc-1]); 904 0 stevel #endif 905 0 stevel pargcp = pargs; 906 0 stevel pnleft = BUFSIZ - 4; 907 0 stevel } 908 0 stevel 909 0 stevel 910 0 stevel 911 0 stevel /* 912 0 stevel * returns pathname of the form dir/file; 913 0 stevel * dir is a null-terminated string; 914 0 stevel */ 915 0 stevel char * 916 356 muffin makename(char *dir, char *file) 917 0 stevel { 918 0 stevel /* 919 0 stevel * Maximum length of a 920 0 stevel * file/dir name in ls-command; 921 0 stevel * dfile is static as this is returned 922 0 stevel * by makename(); 923 0 stevel */ 924 0 stevel static char dfile[MAXNAMLEN]; 925 0 stevel 926 356 muffin char *dp, *fp; 927 0 stevel 928 0 stevel dp = dfile; 929 0 stevel fp = dir; 930 0 stevel while (*fp) 931 0 stevel *dp++ = *fp++; 932 0 stevel if (dp > dfile && *(dp - 1) != '/') 933 0 stevel *dp++ = '/'; 934 0 stevel fp = file; 935 0 stevel while (*fp) 936 0 stevel *dp++ = *fp++; 937 0 stevel *dp = '\0'; 938 0 stevel /* 939 0 stevel * dfile points to the absolute pathname. We are 940 0 stevel * only interested in the last component. 941 0 stevel */ 942 0 stevel return (rindex(dfile, '/') + 1); 943 0 stevel } 944 0 stevel 945 356 muffin int 946 356 muffin sh_bracket_exp(tchar t_ch, tchar t_fch, tchar t_lch) 947 0 stevel { 948 0 stevel char t_char[MB_LEN_MAX + 1]; 949 0 stevel char t_patan[MB_LEN_MAX * 2 + 8]; 950 0 stevel char *p; 951 0 stevel int i; 952 0 stevel 953 0 stevel if ((t_ch == t_fch) || (t_ch == t_lch)) 954 559 nakanon return (1); 955 559 nakanon 956 0 stevel p = t_patan; 957 0 stevel if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0) 958 559 nakanon return (0); 959 0 stevel t_char[i] = 0; 960 0 stevel 961 0 stevel *p++ = '['; 962 0 stevel if ((i = wctomb(p, (wchar_t)t_fch)) <= 0) 963 559 nakanon return (0); 964 0 stevel p += i; 965 0 stevel *p++ = '-'; 966 0 stevel if ((i = wctomb(p, (wchar_t)t_lch)) <= 0) 967 559 nakanon return (0); 968 0 stevel p += i; 969 0 stevel *p++ = ']'; 970 0 stevel *p = 0; 971 0 stevel 972 0 stevel if (fnmatch(t_patan, t_char, FNM_NOESCAPE)) 973 559 nakanon return (0); 974 559 nakanon return (1); 975 0 stevel } 976