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