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