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