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