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