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