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