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 *
globtilde(Char ** nv,Char * s)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
globbrace(Char * s,Char * p,Char *** bl)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
expbrace(Char *** nvp,Char *** elp,size_t size)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 **
globexpand(Char ** v)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 *
handleone(Char * str,Char ** vl,int action)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 **
libglob(Char ** vl)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 *
globone(Char * str,int action)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 **
globall(Char ** v)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
ginit(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
rscan(Char ** t,void (* f)(int))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
trim(Char ** t)531 trim(Char **t)
532 {
533 Char *p;
534
535 while ((p = *t++) != NULL)
536 while (*p)
537 *p++ &= TRIM;
538 }
539
540 void
tglob(Char ** t)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 **
dobackp(Char * cp,int literal)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
backeval(Char * cp,int literal)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
psave(int c)767 psave(int c)
768 {
769 if (--pnleft <= 0)
770 stderror(ERR_WTOOLONG);
771 *pargcp++ = (Char)c;
772 }
773
774 static void
pword(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
Gmatch(Char * string,Char * pattern)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
pmatch(const Char * name,const Char * pat)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
Gcat(Char * s1,Char * s2)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
sortscmp(const void * va,const void * vb)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