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