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 *
globtilde(Char ** nv,Char * s)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
globbrace(Char * s,Char * p,Char *** bl)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
expbrace(Char *** nvp,Char *** elp,int size)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 **
globexpand(Char ** v)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 *
handleone(Char * str,Char ** vl,int action)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 **
libglob(Char ** vl)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 *
globone(Char * str,int action)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 **
globall(Char ** v)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
ginit(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
rscan(Char ** t,void (* f)(int))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
trim(Char ** t)524 trim(Char **t)
525 {
526 Char *p;
527
528 while ((p = *t++) != NULL)
529 while (*p)
530 *p++ &= TRIM;
531 }
532
533 void
tglob(Char ** t)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 **
dobackp(Char * cp,bool literal)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
backeval(Char * cp,bool literal)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
psave(int c)750 psave(int c)
751 {
752 if (--pnleft <= 0)
753 stderror(ERR_WTOOLONG);
754 *pargcp++ = c;
755 }
756
757 static void
pword(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
Gmatch(Char * string,Char * pattern)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
pmatch(Char * string,Char * pattern)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
Gcat(Char * s1,Char * s2)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
sortscmp(const void * a,const void * b)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