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