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