glob.c revision 1.19 1 /* $NetBSD: glob.c,v 1.19 2001/11/03 13:35:39 lukem 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.19 2001/11/03 13:35:39 lukem 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 while (*cp)
691 *cp++ &= TRIM;
692
693 /*
694 * In the child ``forget'' everything about current aliases or
695 * eval vectors.
696 */
697 alvec = NULL;
698 evalvec = NULL;
699 alvecp = NULL;
700 evalp = NULL;
701 (void) lex(&fparaml);
702 if (seterr)
703 stderror(ERR_OLD);
704 alias(&fparaml);
705 t = syntax(fparaml.next, &fparaml, 0);
706 if (seterr)
707 stderror(ERR_OLD);
708 if (t)
709 t->t_dflg |= F_NOFORK;
710 (void)signal(SIGTSTP, SIG_IGN);
711 (void)signal(SIGTTIN, SIG_IGN);
712 (void)signal(SIGTTOU, SIG_IGN);
713 execute(t, -1, NULL, NULL);
714 exitstat();
715 }
716 xfree((ptr_t)cp);
717 (void)close(pvec[1]);
718 c = 0;
719 ip = NULL;
720 do {
721 int cnt;
722
723 cnt = 0;
724
725 for (;;) {
726 if (icnt == 0) {
727 int i;
728
729 ip = ibuf;
730 do
731 icnt = read(pvec[0], tibuf, BUFSIZE);
732 while (icnt == -1 && errno == EINTR);
733 if (icnt <= 0) {
734 c = -1;
735 break;
736 }
737 for (i = 0; i < icnt; i++)
738 ip[i] = (unsigned char) tibuf[i];
739 }
740 if (hadnl)
741 break;
742 --icnt;
743 c = (*ip++ & TRIM);
744 if (c == 0)
745 break;
746 if (c == '\n') {
747 /*
748 * Continue around the loop one more time, so that we can eat
749 * the last newline without terminating this word.
750 */
751 hadnl = 1;
752 continue;
753 }
754 if (!quoted && (c == ' ' || c == '\t'))
755 break;
756 cnt++;
757 psave(c | quoted);
758 }
759 /*
760 * Unless at end-of-file, we will form a new word here if there were
761 * characters in the word, or in any case when we take text literally.
762 * If we didn't make empty words here when literal was set then we
763 * would lose blank lines.
764 */
765 if (c != -1 && (cnt || literal))
766 pword();
767 hadnl = 0;
768 } while (c >= 0);
769 (void)close(pvec[0]);
770 pwait();
771 prestjob();
772 }
773
774 static void
775 psave(int c)
776 {
777 if (--pnleft <= 0)
778 stderror(ERR_WTOOLONG);
779 *pargcp++ = c;
780 }
781
782 static void
783 pword(void)
784 {
785 psave(0);
786 if (pargc == pargsiz - 1) {
787 pargsiz += GLOBSPACE;
788 pargv = (Char **)xrealloc((ptr_t)pargv,
789 (size_t)pargsiz * sizeof(Char *));
790 }
791 pargv[pargc++] = Strsave(pargs);
792 pargv[pargc] = NULL;
793 pargcp = pargs;
794 pnleft = MAXPATHLEN - 4;
795 }
796
797 int
798 Gmatch(Char *string, Char *pattern)
799 {
800 Char **blk, **p;
801 int gpol, gres;
802
803 gpol = 1;
804 gres = 0;
805
806 if (*pattern == '^') {
807 gpol = 0;
808 pattern++;
809 }
810
811 blk = (Char **)xmalloc(GLOBSPACE * sizeof(Char *));
812 blk[0] = Strsave(pattern);
813 blk[1] = NULL;
814
815 expbrace(&blk, NULL, GLOBSPACE);
816
817 for (p = blk; *p; p++)
818 gres |= pmatch(string, *p);
819
820 blkfree(blk);
821 return(gres == gpol);
822 }
823
824 static int
825 pmatch(Char *string, Char *pattern)
826 {
827 int match, negate_range;
828 Char patternc, rangec, stringc;
829
830 for (;; ++string) {
831 stringc = *string & TRIM;
832 patternc = *pattern++;
833 switch (patternc) {
834 case 0:
835 return (stringc == 0);
836 case '?':
837 if (stringc == 0)
838 return (0);
839 break;
840 case '*':
841 if (!*pattern)
842 return (1);
843 while (*string)
844 if (Gmatch(string++, pattern))
845 return (1);
846 return (0);
847 case '[':
848 match = 0;
849 if ((negate_range = (*pattern == '^')) != 0)
850 pattern++;
851 while ((rangec = *pattern++) != '\0') {
852 if (rangec == ']')
853 break;
854 if (match)
855 continue;
856 if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') {
857 match = (stringc <= (*pattern & TRIM) &&
858 (*(pattern-2) & TRIM) <= stringc);
859 pattern++;
860 }
861 else
862 match = (stringc == (rangec & TRIM));
863 }
864 if (rangec == 0)
865 stderror(ERR_NAME | ERR_MISSING, ']');
866 if (match == negate_range)
867 return (0);
868 break;
869 default:
870 if ((patternc & TRIM) != stringc)
871 return (0);
872 break;
873
874 }
875 }
876 }
877
878 void
879 Gcat(Char *s1, Char *s2)
880 {
881 Char *p, *q;
882 int n;
883
884 for (p = s1; *p++;)
885 continue;
886 for (q = s2; *q++;)
887 continue;
888 n = (p - s1) + (q - s2) - 1;
889 if (++gargc >= gargsiz) {
890 gargsiz += GLOBSPACE;
891 gargv = (Char **)xrealloc((ptr_t)gargv,
892 (size_t)gargsiz * sizeof(Char *));
893 }
894 gargv[gargc] = 0;
895 p = gargv[gargc - 1] = (Char *)xmalloc((size_t)n * sizeof(Char));
896 for (q = s1; (*p++ = *q++) != '\0';)
897 continue;
898 for (p--, q = s2; (*p++ = *q++) != '\0';)
899 continue;
900 }
901
902 #ifdef FILEC
903 int
904 sortscmp(const ptr_t a, const ptr_t b)
905 {
906 #if defined(NLS) && !defined(NOSTRCOLL)
907 char buf[2048];
908 #endif
909
910 if (!a) /* check for NULL */
911 return (b ? 1 : 0);
912 if (!b)
913 return (-1);
914
915 if (!*(Char **)a) /* check for NULL */
916 return (*(Char **)b ? 1 : 0);
917 if (!*(Char **)b)
918 return (-1);
919
920 #if defined(NLS) && !defined(NOSTRCOLL)
921 (void)strcpy(buf, short2str(*(Char **)a));
922 return ((int)strcoll(buf, short2str(*(Char **)b)));
923 #else
924 return ((int)Strcmp(*(Char **)a, *(Char **)b));
925 #endif
926 }
927 #endif /* FILEC */
928