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