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