1 /* $NetBSD: glob.c,v 1.19 2001/11/03 13:35:39 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)glob.c 8.1 (Berkeley) 5/31/93"; 40 #else 41 __RCSID("$NetBSD: glob.c,v 1.19 2001/11/03 13:35:39 lukem Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 47 #include <errno.h> 48 #include <glob.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #if __STDC__ 54 # include <stdarg.h> 55 #else 56 # include <varargs.h> 57 #endif 58 59 #include "csh.h" 60 #include "extern.h" 61 62 static int noglob; 63 static int gargsiz, pargsiz; 64 65 /* 66 * Values for gflag 67 */ 68 #define G_NONE 0 /* No globbing needed */ 69 #define G_GLOB 1 /* string contains *?[] characters */ 70 #define G_CSH 2 /* string contains ~`{ characters */ 71 72 #define GLOBSPACE 100 /* Alloc increment */ 73 74 #define LBRC '{' 75 #define RBRC '}' 76 #define LBRK '[' 77 #define RBRK ']' 78 #define EOS '\0' 79 80 Char **gargv = NULL; 81 Char **pargv = NULL; 82 long gargc = 0; 83 long pargc = 0; 84 85 /* 86 * globbing is now done in two stages. In the first pass we expand 87 * csh globbing idioms ~`{ and then we proceed doing the normal 88 * globbing if needed ?*[ 89 * 90 * Csh type globbing is handled in globexpand() and the rest is 91 * handled in glob() which is part of the 4.4BSD libc. 92 * 93 */ 94 static Char *globtilde(Char **, Char *); 95 static Char *handleone(Char *, Char **, int); 96 static Char **libglob(Char **); 97 static Char **globexpand(Char **); 98 static int globbrace(Char *, Char *, Char ***); 99 static void expbrace(Char ***, Char ***, int); 100 static int pmatch(Char *, Char *); 101 static void pword(void); 102 static void psave(int); 103 static void backeval(Char *, bool); 104 105 static Char * 106 globtilde(Char **nv, Char *s) 107 { 108 Char gbuf[MAXPATHLEN], *b, *e, *gstart, *u; 109 110 gstart = gbuf; 111 *gstart++ = *s++; 112 u = s; 113 for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; 114 *s && *s != '/' && *s != ':' && b < e; 115 *b++ = *s++) 116 continue; 117 *b = EOS; 118 if (gethdir(gstart)) { 119 blkfree(nv); 120 if (*gstart) 121 stderror(ERR_UNKUSER, vis_str(gstart)); 122 else 123 stderror(ERR_NOHOME); 124 } 125 b = &gstart[Strlen(gstart)]; 126 while (*s) 127 *b++ = *s++; 128 *b = EOS; 129 --u; 130 xfree((ptr_t) u); 131 return (Strsave(gstart)); 132 } 133 134 static int 135 globbrace(Char *s, Char *p, Char ***bl) 136 { 137 Char gbuf[MAXPATHLEN]; 138 Char *lm, *pe, *pl, *pm, **nv, **vl; 139 int i, len, size; 140 141 size = GLOBSPACE; 142 nv = vl = (Char **)xmalloc((size_t) sizeof(Char *) * size); 143 *vl = NULL; 144 len = 0; 145 /* copy part up to the brace */ 146 for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) 147 continue; 148 149 /* check for balanced braces */ 150 for (i = 0, pe = ++p; *pe; pe++) 151 if (*pe == LBRK) { 152 /* Ignore everything between [] */ 153 for (++pe; *pe != RBRK && *pe != EOS; pe++) 154 continue; 155 if (*pe == EOS) { 156 blkfree(nv); 157 return (-RBRK); 158 } 159 } 160 else if (*pe == LBRC) 161 i++; 162 else if (*pe == RBRC) { 163 if (i == 0) 164 break; 165 i--; 166 } 167 168 if (i != 0 || *pe == '\0') { 169 blkfree(nv); 170 return (-RBRC); 171 } 172 173 for (i = 0, pl = pm = p; pm <= pe; pm++) 174 switch (*pm) { 175 case LBRK: 176 for (++pm; *pm != RBRK && *pm != EOS; pm++) 177 continue; 178 if (*pm == EOS) { 179 *vl = NULL; 180 blkfree(nv); 181 return (-RBRK); 182 } 183 break; 184 case LBRC: 185 i++; 186 break; 187 case RBRC: 188 if (i) { 189 i--; 190 break; 191 } 192 /* FALLTHROUGH */ 193 case ',': 194 if (i && *pm == ',') 195 break; 196 else { 197 Char savec = *pm; 198 199 *pm = EOS; 200 (void)Strcpy(lm, pl); 201 (void)Strcat(gbuf, pe + 1); 202 *pm = savec; 203 *vl++ = Strsave(gbuf); 204 len++; 205 pl = pm + 1; 206 if (vl == &nv[size]) { 207 size += GLOBSPACE; 208 nv = (Char **)xrealloc((ptr_t) nv, 209 (size_t)size * sizeof(Char *)); 210 vl = &nv[size - GLOBSPACE]; 211 } 212 } 213 break; 214 default: 215 break; 216 } 217 *vl = NULL; 218 *bl = nv; 219 return (len); 220 } 221 222 static void 223 expbrace(Char ***nvp, Char ***elp, int size) 224 { 225 Char **el, **nv, *s, **vl; 226 227 vl = nv = *nvp; 228 if (elp != NULL) 229 el = *elp; 230 else 231 for (el = vl; *el; el++) 232 continue; 233 234 for (s = *vl; s; s = *++vl) { 235 Char *b, **bp, **vp; 236 237 /* leave {} untouched for find */ 238 if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) 239 continue; 240 if ((b = Strchr(s, '{')) != NULL) { 241 Char **bl; 242 int len; 243 244 if ((len = globbrace(s, b, &bl)) < 0) { 245 xfree((ptr_t)nv); 246 stderror(ERR_MISSING, -len); 247 } 248 xfree((ptr_t) s); 249 if (len == 1) { 250 *vl-- = *bl; 251 xfree((ptr_t) bl); 252 continue; 253 } 254 len = blklen(bl); 255 if (&el[len] >= &nv[size]) { 256 int e, l; 257 258 l = &el[len] - &nv[size]; 259 size += GLOBSPACE > l ? GLOBSPACE : l; 260 l = vl - nv; 261 e = el - nv; 262 nv = (Char **)xrealloc((ptr_t)nv, 263 (size_t)size * sizeof(Char *)); 264 vl = nv + l; 265 el = nv + e; 266 } 267 vp = vl--; 268 *vp = *bl; 269 len--; 270 for (bp = el; bp != vp; bp--) 271 bp[len] = *bp; 272 el += len; 273 vp++; 274 for (bp = bl + 1; *bp; *vp++ = *bp++) 275 continue; 276 xfree((ptr_t)bl); 277 } 278 279 } 280 if (elp != NULL) 281 *elp = el; 282 *nvp = nv; 283 } 284 285 static Char ** 286 globexpand(Char **v) 287 { 288 Char **el, **nv, *s, **vl; 289 int size; 290 291 size = GLOBSPACE; 292 nv = vl = (Char **)xmalloc((size_t)sizeof(Char *) * size); 293 *vl = NULL; 294 295 /* 296 * Step 1: expand backquotes. 297 */ 298 while ((s = *v++) != NULL) { 299 if (Strchr(s, '`')) { 300 int i; 301 302 (void) dobackp(s, 0); 303 for (i = 0; i < pargc; i++) { 304 *vl++ = pargv[i]; 305 if (vl == &nv[size]) { 306 size += GLOBSPACE; 307 nv = (Char **)xrealloc((ptr_t) nv, 308 (size_t)size * sizeof(Char *)); 309 vl = &nv[size - GLOBSPACE]; 310 } 311 } 312 xfree((ptr_t)pargv); 313 pargv = NULL; 314 } 315 else { 316 *vl++ = Strsave(s); 317 if (vl == &nv[size]) { 318 size += GLOBSPACE; 319 nv = (Char **)xrealloc((ptr_t)nv, 320 (size_t)size * sizeof(Char *)); 321 vl = &nv[size - GLOBSPACE]; 322 } 323 } 324 } 325 *vl = NULL; 326 327 if (noglob) 328 return (nv); 329 330 /* 331 * Step 2: expand braces 332 */ 333 el = vl; 334 expbrace(&nv, &el, size); 335 336 /* 337 * Step 3: expand ~ 338 */ 339 vl = nv; 340 for (s = *vl; s; s = *++vl) 341 if (*s == '~') 342 *vl = globtilde(nv, s); 343 vl = nv; 344 return (vl); 345 } 346 347 static Char * 348 handleone(Char *str, Char **vl, int action) 349 { 350 Char *cp, **vlp; 351 352 vlp = vl; 353 switch (action) { 354 case G_ERROR: 355 setname(vis_str(str)); 356 blkfree(vl); 357 stderror(ERR_NAME | ERR_AMBIG); 358 /* NOTREACHED */ 359 case G_APPEND: 360 trim(vlp); 361 str = Strsave(*vlp++); 362 do { 363 cp = Strspl(str, STRspace); 364 xfree((ptr_t)str); 365 str = Strspl(cp, *vlp); 366 xfree((ptr_t)cp); 367 } 368 while (*++vlp); 369 blkfree(vl); 370 break; 371 case G_IGNORE: 372 str = Strsave(strip(*vlp)); 373 blkfree(vl); 374 break; 375 default: 376 break; 377 } 378 return (str); 379 } 380 381 static Char ** 382 libglob(Char **vl) 383 { 384 glob_t globv; 385 char *ptr; 386 int gflgs, magic, match, nonomatch; 387 388 gflgs = GLOB_NOMAGIC; 389 magic = 0; 390 match = 0; 391 nonomatch = adrof(STRnonomatch) != 0; 392 393 if (!vl || !vl[0]) 394 return (vl); 395 396 globv.gl_offs = 0; 397 globv.gl_pathv = 0; 398 globv.gl_pathc = 0; 399 400 if (nonomatch) 401 gflgs |= GLOB_NOCHECK; 402 403 do { 404 ptr = short2qstr(*vl); 405 switch (glob(ptr, gflgs, 0, &globv)) { 406 case GLOB_ABORTED: 407 setname(vis_str(*vl)); 408 stderror(ERR_NAME | ERR_GLOB); 409 /* NOTREACHED */ 410 case GLOB_NOSPACE: 411 stderror(ERR_NOMEM); 412 /* NOTREACHED */ 413 default: 414 break; 415 } 416 if (globv.gl_flags & GLOB_MAGCHAR) { 417 match |= (globv.gl_matchc != 0); 418 magic = 1; 419 } 420 gflgs |= GLOB_APPEND; 421 } 422 while (*++vl); 423 vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? 424 NULL : blk2short(globv.gl_pathv); 425 globfree(&globv); 426 return (vl); 427 } 428 429 Char * 430 globone(Char *str, int action) 431 { 432 Char *v[2], **vl, **vo; 433 int gflg; 434 435 noglob = adrof(STRnoglob) != 0; 436 gflag = 0; 437 v[0] = str; 438 v[1] = 0; 439 tglob(v); 440 gflg = gflag; 441 if (gflg == G_NONE) 442 return (strip(Strsave(str))); 443 444 if (gflg & G_CSH) { 445 /* 446 * Expand back-quote, tilde and brace 447 */ 448 vo = globexpand(v); 449 if (noglob || (gflg & G_GLOB) == 0) { 450 if (vo[0] == NULL) { 451 xfree((ptr_t)vo); 452 return (Strsave(STRNULL)); 453 } 454 if (vo[1] != NULL) 455 return (handleone(str, vo, action)); 456 else { 457 str = strip(vo[0]); 458 xfree((ptr_t) vo); 459 return (str); 460 } 461 } 462 } 463 else if (noglob || (gflg & G_GLOB) == 0) 464 return (strip(Strsave(str))); 465 else 466 vo = v; 467 468 vl = libglob(vo); 469 if ((gflg & G_CSH) && vl != vo) 470 blkfree(vo); 471 if (vl == NULL) { 472 setname(vis_str(str)); 473 stderror(ERR_NAME | ERR_NOMATCH); 474 } 475 if (vl[0] == NULL) { 476 xfree((ptr_t)vl); 477 return (Strsave(STRNULL)); 478 } 479 if (vl[1] != NULL) 480 return (handleone(str, vl, action)); 481 else { 482 str = strip(*vl); 483 xfree((ptr_t)vl); 484 return (str); 485 } 486 } 487 488 Char ** 489 globall(Char **v) 490 { 491 Char **vl, **vo; 492 int gflg; 493 494 gflg = gflag; 495 if (!v || !v[0]) { 496 gargv = saveblk(v); 497 gargc = blklen(gargv); 498 return (gargv); 499 } 500 501 noglob = adrof(STRnoglob) != 0; 502 503 if (gflg & G_CSH) 504 /* 505 * Expand back-quote, tilde and brace 506 */ 507 vl = vo = globexpand(v); 508 else 509 vl = vo = saveblk(v); 510 511 if (!noglob && (gflg & G_GLOB)) { 512 vl = libglob(vo); 513 if ((gflg & G_CSH) && vl != vo) 514 blkfree(vo); 515 } 516 else 517 trim(vl); 518 519 gargc = vl ? blklen(vl) : 0; 520 return (gargv = vl); 521 } 522 523 void 524 ginit(void) 525 { 526 gargsiz = GLOBSPACE; 527 gargv = (Char **)xmalloc((size_t)sizeof(Char *) * gargsiz); 528 gargv[0] = 0; 529 gargc = 0; 530 } 531 532 void 533 rscan(Char **t, void (*f)(int)) 534 { 535 Char *p; 536 537 while ((p = *t++) != NULL) 538 while (*p) 539 (*f) (*p++); 540 } 541 542 void 543 trim(Char **t) 544 { 545 Char *p; 546 547 while ((p = *t++) != NULL) 548 while (*p) 549 *p++ &= TRIM; 550 } 551 552 void 553 tglob(Char **t) 554 { 555 Char *p, c; 556 557 while ((p = *t++) != NULL) { 558 if (*p == '~' || *p == '=') 559 gflag |= G_CSH; 560 else if (*p == '{' && 561 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) 562 continue; 563 while ((c = *p++) != '\0') { 564 /* 565 * eat everything inside the matching backquotes 566 */ 567 if (c == '`') { 568 gflag |= G_CSH; 569 while (*p && *p != '`') 570 if (*p++ == '\\') { 571 if (*p) /* Quoted chars */ 572 p++; 573 else 574 break; 575 } 576 if (*p) /* The matching ` */ 577 p++; 578 else 579 break; 580 } 581 else if (c == '{') 582 gflag |= G_CSH; 583 else if (isglob(c)) 584 gflag |= G_GLOB; 585 } 586 } 587 } 588 589 /* 590 * Command substitute cp. If literal, then this is a substitution from a 591 * << redirection, and so we should not crunch blanks and tabs, separating 592 * words only at newlines. 593 */ 594 Char ** 595 dobackp(Char *cp, bool literal) 596 { 597 Char word[MAXPATHLEN], *ep, *lp, *rp; 598 599 if (pargv) { 600 #ifdef notdef 601 abort(); 602 #endif 603 blkfree(pargv); 604 } 605 pargsiz = GLOBSPACE; 606 pargv = (Char **)xmalloc((size_t)sizeof(Char *) * pargsiz); 607 pargv[0] = NULL; 608 pargcp = pargs = word; 609 pargc = 0; 610 pnleft = MAXPATHLEN - 4; 611 for (;;) { 612 for (lp = cp; *lp != '`'; lp++) { 613 if (*lp == 0) { 614 if (pargcp != pargs) 615 pword(); 616 return (pargv); 617 } 618 psave(*lp); 619 } 620 lp++; 621 for (rp = lp; *rp && *rp != '`'; rp++) 622 if (*rp == '\\') { 623 rp++; 624 if (!*rp) 625 goto oops; 626 } 627 if (!*rp) { 628 oops: 629 stderror(ERR_UNMATCHED, '`'); 630 } 631 ep = Strsave(lp); 632 ep[rp - lp] = 0; 633 backeval(ep, literal); 634 cp = rp + 1; 635 } 636 } 637 638 static void 639 backeval(Char *cp, bool literal) 640 { 641 struct command faket; 642 char tibuf[BUFSIZE]; 643 Char ibuf[BUFSIZE], *fakecom[2], *ip; 644 int pvec[2], c, icnt, quoted; 645 bool hadnl; 646 647 hadnl = 0; 648 icnt = 0; 649 quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; 650 faket.t_dtyp = NODE_COMMAND; 651 faket.t_dflg = 0; 652 faket.t_dlef = 0; 653 faket.t_drit = 0; 654 faket.t_dspr = 0; 655 faket.t_dcom = fakecom; 656 fakecom[0] = STRfakecom1; 657 fakecom[1] = 0; 658 659 /* 660 * We do the psave job to temporarily change the current job so that the 661 * following fork is considered a separate job. This is so that when 662 * backquotes are used in a builtin function that calls glob the "current 663 * job" is not corrupted. We only need one level of pushed jobs as long as 664 * we are sure to fork here. 665 */ 666 psavejob(); 667 668 /* 669 * It would be nicer if we could integrate this redirection more with the 670 * routines in sh.sem.c by doing a fake execute on a builtin function that 671 * was piped out. 672 */ 673 mypipe(pvec); 674 if (pfork(&faket, -1) == 0) { 675 struct wordent fparaml; 676 struct command *t; 677 678 (void)close(pvec[0]); 679 (void)dmove(pvec[1], 1); 680 (void)dmove(SHERR, 2); 681 initdesc(); 682 /* 683 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, 684 * posted to comp.bugs.4bsd 12 Sep. 1989. 685 */ 686 if (pargv) /* mg, 21.dec.88 */ 687 blkfree(pargv), pargv = 0, pargsiz = 0; 688 /* mg, 21.dec.88 */ 689 arginp = cp; 690 while (*cp) 691 *cp++ &= TRIM; 692 693 /* 694 * In the child ``forget'' everything about current aliases or 695 * eval vectors. 696 */ 697 alvec = NULL; 698 evalvec = NULL; 699 alvecp = NULL; 700 evalp = NULL; 701 (void) lex(&fparaml); 702 if (seterr) 703 stderror(ERR_OLD); 704 alias(&fparaml); 705 t = syntax(fparaml.next, &fparaml, 0); 706 if (seterr) 707 stderror(ERR_OLD); 708 if (t) 709 t->t_dflg |= F_NOFORK; 710 (void)signal(SIGTSTP, SIG_IGN); 711 (void)signal(SIGTTIN, SIG_IGN); 712 (void)signal(SIGTTOU, SIG_IGN); 713 execute(t, -1, NULL, NULL); 714 exitstat(); 715 } 716 xfree((ptr_t)cp); 717 (void)close(pvec[1]); 718 c = 0; 719 ip = NULL; 720 do { 721 int cnt; 722 723 cnt = 0; 724 725 for (;;) { 726 if (icnt == 0) { 727 int i; 728 729 ip = ibuf; 730 do 731 icnt = read(pvec[0], tibuf, BUFSIZE); 732 while (icnt == -1 && errno == EINTR); 733 if (icnt <= 0) { 734 c = -1; 735 break; 736 } 737 for (i = 0; i < icnt; i++) 738 ip[i] = (unsigned char) tibuf[i]; 739 } 740 if (hadnl) 741 break; 742 --icnt; 743 c = (*ip++ & TRIM); 744 if (c == 0) 745 break; 746 if (c == '\n') { 747 /* 748 * Continue around the loop one more time, so that we can eat 749 * the last newline without terminating this word. 750 */ 751 hadnl = 1; 752 continue; 753 } 754 if (!quoted && (c == ' ' || c == '\t')) 755 break; 756 cnt++; 757 psave(c | quoted); 758 } 759 /* 760 * Unless at end-of-file, we will form a new word here if there were 761 * characters in the word, or in any case when we take text literally. 762 * If we didn't make empty words here when literal was set then we 763 * would lose blank lines. 764 */ 765 if (c != -1 && (cnt || literal)) 766 pword(); 767 hadnl = 0; 768 } while (c >= 0); 769 (void)close(pvec[0]); 770 pwait(); 771 prestjob(); 772 } 773 774 static void 775 psave(int c) 776 { 777 if (--pnleft <= 0) 778 stderror(ERR_WTOOLONG); 779 *pargcp++ = c; 780 } 781 782 static void 783 pword(void) 784 { 785 psave(0); 786 if (pargc == pargsiz - 1) { 787 pargsiz += GLOBSPACE; 788 pargv = (Char **)xrealloc((ptr_t)pargv, 789 (size_t)pargsiz * sizeof(Char *)); 790 } 791 pargv[pargc++] = Strsave(pargs); 792 pargv[pargc] = NULL; 793 pargcp = pargs; 794 pnleft = MAXPATHLEN - 4; 795 } 796 797 int 798 Gmatch(Char *string, Char *pattern) 799 { 800 Char **blk, **p; 801 int gpol, gres; 802 803 gpol = 1; 804 gres = 0; 805 806 if (*pattern == '^') { 807 gpol = 0; 808 pattern++; 809 } 810 811 blk = (Char **)xmalloc(GLOBSPACE * sizeof(Char *)); 812 blk[0] = Strsave(pattern); 813 blk[1] = NULL; 814 815 expbrace(&blk, NULL, GLOBSPACE); 816 817 for (p = blk; *p; p++) 818 gres |= pmatch(string, *p); 819 820 blkfree(blk); 821 return(gres == gpol); 822 } 823 824 static int 825 pmatch(Char *string, Char *pattern) 826 { 827 int match, negate_range; 828 Char patternc, rangec, stringc; 829 830 for (;; ++string) { 831 stringc = *string & TRIM; 832 patternc = *pattern++; 833 switch (patternc) { 834 case 0: 835 return (stringc == 0); 836 case '?': 837 if (stringc == 0) 838 return (0); 839 break; 840 case '*': 841 if (!*pattern) 842 return (1); 843 while (*string) 844 if (Gmatch(string++, pattern)) 845 return (1); 846 return (0); 847 case '[': 848 match = 0; 849 if ((negate_range = (*pattern == '^')) != 0) 850 pattern++; 851 while ((rangec = *pattern++) != '\0') { 852 if (rangec == ']') 853 break; 854 if (match) 855 continue; 856 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { 857 match = (stringc <= (*pattern & TRIM) && 858 (*(pattern-2) & TRIM) <= stringc); 859 pattern++; 860 } 861 else 862 match = (stringc == (rangec & TRIM)); 863 } 864 if (rangec == 0) 865 stderror(ERR_NAME | ERR_MISSING, ']'); 866 if (match == negate_range) 867 return (0); 868 break; 869 default: 870 if ((patternc & TRIM) != stringc) 871 return (0); 872 break; 873 874 } 875 } 876 } 877 878 void 879 Gcat(Char *s1, Char *s2) 880 { 881 Char *p, *q; 882 int n; 883 884 for (p = s1; *p++;) 885 continue; 886 for (q = s2; *q++;) 887 continue; 888 n = (p - s1) + (q - s2) - 1; 889 if (++gargc >= gargsiz) { 890 gargsiz += GLOBSPACE; 891 gargv = (Char **)xrealloc((ptr_t)gargv, 892 (size_t)gargsiz * sizeof(Char *)); 893 } 894 gargv[gargc] = 0; 895 p = gargv[gargc - 1] = (Char *)xmalloc((size_t)n * sizeof(Char)); 896 for (q = s1; (*p++ = *q++) != '\0';) 897 continue; 898 for (p--, q = s2; (*p++ = *q++) != '\0';) 899 continue; 900 } 901 902 #ifdef FILEC 903 int 904 sortscmp(const ptr_t a, const ptr_t b) 905 { 906 #if defined(NLS) && !defined(NOSTRCOLL) 907 char buf[2048]; 908 #endif 909 910 if (!a) /* check for NULL */ 911 return (b ? 1 : 0); 912 if (!b) 913 return (-1); 914 915 if (!*(Char **)a) /* check for NULL */ 916 return (*(Char **)b ? 1 : 0); 917 if (!*(Char **)b) 918 return (-1); 919 920 #if defined(NLS) && !defined(NOSTRCOLL) 921 (void)strcpy(buf, short2str(*(Char **)a)); 922 return ((int)strcoll(buf, short2str(*(Char **)b))); 923 #else 924 return ((int)Strcmp(*(Char **)a, *(Char **)b)); 925 #endif 926 } 927 #endif /* FILEC */ 928