source: trunk/third/tcsh/sh.glob.c @ 9006

Revision 9006, 21.6 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9005, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.glob.c,v 1.1.1.1 1996-10-02 06:09:21 ghudson Exp $ */
2/*
3 * sh.glob.c: Regular expression expansion
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by the University of
20 *      California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: sh.glob.c,v 1.1.1.1 1996-10-02 06:09:21 ghudson Exp $")
40
41#include "tc.h"
42
43#include "glob.h"
44
45static int noglob;
46static int pargsiz, gargsiz;
47
48/*
49 * Values for gflag
50 */
51#define G_NONE  0               /* No globbing needed                   */
52#define G_GLOB  1               /* string contains *?[] characters      */
53#define G_CSH   2               /* string contains ~`{ characters       */
54
55#define GLOBSPACE       100     /* Alloc increment                      */
56
57#define LBRC '{'
58#define RBRC '}'
59#define LBRK '['
60#define RBRK ']'
61#define EOS '\0'
62
63Char  **gargv = NULL;
64long    gargc = 0;
65Char  **pargv = NULL;
66static long    pargc = 0;
67
68/*
69 * globbing is now done in two stages. In the first pass we expand
70 * csh globbing idioms ~`{ and then we proceed doing the normal
71 * globbing if needed ?*[
72 *
73 * Csh type globbing is handled in globexpand() and the rest is
74 * handled in glob() which is part of the 4.4BSD libc.
75 *
76 */
77static  Char     *globtilde     __P((Char **, Char *));
78static  Char    **libglob       __P((Char **));
79static  Char    **globexpand    __P((Char **));
80static  int       globbrace     __P((Char *, Char *, Char ***));
81static  void      expbrace      __P((Char ***, Char ***, int));
82static  int       pmatch        __P((Char *, Char *, Char **));
83static  void      pword         __P((void));
84static  void      psave         __P((int));
85static  void      backeval      __P((Char *, bool));
86
87static Char *
88globtilde(nv, s)
89    Char  **nv, *s;
90{
91    Char    gbuf[BUFSIZE], *gstart, *b, *u, *e;
92#ifdef apollo
93    int slash;
94#endif
95
96    gstart = gbuf;
97    *gstart++ = *s++;
98    u = s;
99    for (b = gstart, e = &gbuf[BUFSIZE - 1];
100         *s && *s != '/' && *s != ':' && b < e;
101         *b++ = *s++)
102        continue;
103    *b = EOS;
104    if (gethdir(gstart)) {
105        blkfree(nv);
106        if (*gstart)
107            stderror(ERR_UNKUSER, short2str(gstart));
108        else
109            stderror(ERR_NOHOME);
110    }
111    b = &gstart[Strlen(gstart)];
112#ifdef apollo
113    slash = gstart[0] == '/' && gstart[1] == '\0';
114#endif
115    while (*s)
116        *b++ = *s++;
117    *b = EOS;
118    --u;
119    xfree((ptr_t) u);
120#ifdef apollo
121    if (slash && gstart[1] == '/')
122        gstart++;
123#endif
124    return (Strsave(gstart));
125}
126
127Char *
128globequal(new, old)
129    Char *new, *old;
130{
131    int     dig;
132    Char    *b, *d;
133
134    /*
135     * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
136     * in stack. PWP: let =foobar pass through (for X windows)
137     */
138    if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
139        /* =- */
140        dig = -1;
141        b = &old[2];
142    }
143    else if (Isdigit(old[1])) {
144        /* =<number> */
145        dig = old[1] - '0';
146        for (b = &old[2]; Isdigit(*b); b++)
147            dig = dig * 10 + (*b - '0');
148        if (*b != '\0' && *b != '/')
149            /* =<number>foobar */
150            return old;
151    }
152    else
153        /* =foobar */
154        return old;
155
156    if (!getstakd(new, dig))
157        return NULL;
158
159    /* Copy the rest of the string */
160    for (d = &new[Strlen(new)];
161         d < &new[BUFSIZE - 1] && (*d++ = *b++) != '\0';)
162        continue;
163    *d = '\0';
164
165    return new;
166}
167
168static int
169globbrace(s, p, bl)
170    Char   *s, *p, ***bl;
171{
172    int     i, len;
173    Char   *pm, *pe, *lm, *pl;
174    Char  **nv, **vl;
175    Char    gbuf[BUFSIZE];
176    int     size = GLOBSPACE;
177
178    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
179    *vl = NULL;
180
181    len = 0;
182    /* copy part up to the brace */
183    for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++)
184        continue;
185
186    /* check for balanced braces */
187    for (i = 0, pe = ++p; *pe; pe++)
188        if (*pe == LBRK) {
189            /* Ignore everything between [] */
190            for (++pe; *pe != RBRK && *pe != EOS; pe++)
191                continue;
192            if (*pe == EOS) {
193                blkfree(nv);
194                return (-RBRK);
195            }
196        }
197        else if (*pe == LBRC)
198            i++;
199        else if (*pe == RBRC) {
200            if (i == 0)
201                break;
202            i--;
203        }
204
205    if (i != 0 || *pe == '\0') {
206        blkfree(nv);
207        return (-RBRC);
208    }
209
210    for (i = 0, pl = pm = p; pm <= pe; pm++)
211        switch (*pm) {
212        case LBRK:
213            for (++pm; *pm != RBRK && *pm != EOS; pm++)
214                continue;
215            if (*pm == EOS) {
216                *vl = NULL;
217                blkfree(nv);
218                return (-RBRK);
219            }
220            break;
221        case LBRC:
222            i++;
223            break;
224        case RBRC:
225            if (i) {
226                i--;
227                break;
228            }
229            /* FALLTHROUGH */
230        case ',':
231            if (i && *pm == ',')
232                break;
233            else {
234                Char    savec = *pm;
235
236                *pm = EOS;
237                (void) Strcpy(lm, pl);
238                (void) Strcat(gbuf, pe + 1);
239                *pm = savec;
240                *vl++ = Strsave(gbuf);
241                len++;
242                pl = pm + 1;
243                if (vl == &nv[size]) {
244                    size += GLOBSPACE;
245                    nv = (Char **) xrealloc((ptr_t) nv,
246                                            (size_t) (size * sizeof(Char *)));
247                    vl = &nv[size - GLOBSPACE];
248                }
249            }
250            break;
251        default:
252            break;
253        }
254    *vl = NULL;
255    *bl = nv;
256    return (len);
257}
258
259
260static void
261expbrace(nvp, elp, size)
262    Char ***nvp, ***elp;
263    int size;
264{
265    Char **vl, **el, **nv, *s;
266
267    vl = nv = *nvp;
268    if (elp != NULL)
269        el = *elp;
270    else
271        for (el = vl; *el; el++)
272            continue;
273
274    for (s = *vl; s; s = *++vl) {
275        Char   *b;
276        Char  **vp, **bp;
277
278        /* leave {} untouched for find */
279        if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
280            continue;
281        if ((b = Strchr(s, '{')) != NULL) {
282            Char  **bl;
283            int     len;
284
285            if ((len = globbrace(s, b, &bl)) < 0) {
286                xfree((ptr_t) nv);
287                stderror(ERR_MISSING, -len);
288            }
289            xfree((ptr_t) s);
290            if (len == 1) {
291                *vl-- = *bl;
292                xfree((ptr_t) bl);
293                continue;
294            }
295            if (&el[len] >= &nv[size]) {
296                int     l, e;
297                l = &el[len] - &nv[size];
298                size += GLOBSPACE > l ? GLOBSPACE : l;
299                l = vl - nv;
300                e = el - nv;
301                nv = (Char **) xrealloc((ptr_t) nv,
302                                        (size_t) (size * sizeof(Char *)));
303                vl = nv + l;
304                el = nv + e;
305            }
306            /* nv vl   el     bl
307             * |  |    |      |
308             * -.--..--       x--
309             *   |            len
310             *   vp
311             */
312            vp = vl--;
313            *vp = *bl;
314            len--;
315            for (bp = el; bp != vp; bp--)
316                bp[len] = *bp;
317            el += len;
318            /* nv vl    el bl
319             * |  |     |  |
320             * -.-x  ---    --
321             *   |len
322             *   vp
323             */
324            vp++;
325            for (bp = bl + 1; *bp; *vp++ = *bp++)
326                continue;
327            xfree((ptr_t) bl);
328        }
329
330    }
331    if (elp != NULL)
332        *elp = el;
333    *nvp = nv;
334}
335
336static Char **
337globexpand(v)
338    Char  **v;
339{
340    Char   *s;
341    Char  **nv, **vl, **el;
342    int     size = GLOBSPACE;
343
344
345    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
346    *vl = NULL;
347
348    /*
349     * Step 1: expand backquotes.
350     */
351    while ((s = *v++) != '\0') {
352        if (Strchr(s, '`')) {
353            int     i;
354
355            (void) dobackp(s, 0);
356            for (i = 0; i < pargc; i++) {
357                *vl++ = pargv[i];
358                if (vl == &nv[size]) {
359                    size += GLOBSPACE;
360                    nv = (Char **) xrealloc((ptr_t) nv,
361                                            (size_t) (size * sizeof(Char *)));
362                    vl = &nv[size - GLOBSPACE];
363                }
364            }
365            xfree((ptr_t) pargv);
366            pargv = NULL;
367        }
368        else {
369            *vl++ = Strsave(s);
370            if (vl == &nv[size]) {
371                size += GLOBSPACE;
372                nv = (Char **) xrealloc((ptr_t) nv,
373                                        (size_t) (size * sizeof(Char *)));
374                vl = &nv[size - GLOBSPACE];
375            }
376        }
377    }
378    *vl = NULL;
379
380    if (noglob)
381        return (nv);
382
383    /*
384     * Step 2: expand braces
385     */
386    el = vl;
387    expbrace(&nv, &el, size);
388
389
390    /*
391     * Step 3: expand ~ =
392     */
393    vl = nv;
394    for (s = *vl; s; s = *++vl)
395        switch (*s) {
396            Char gp[BUFSIZE], *ns;
397        case '~':
398            *vl = globtilde(nv, s);
399            break;
400        case '=':
401            if ((ns = globequal(gp, s)) == NULL) {
402                /* Error */
403                blkfree(nv);
404                stderror(ERR_DEEP);
405            }
406            if (ns != s) {
407                /* Expansion succeeded */
408                xfree((ptr_t) s);
409                *vl = Strsave(gp);
410            }
411            break;
412        default:
413            break;
414        }
415    vl = nv;
416
417    /*
418     * Step 4: expand .. if the variable symlinks==expand is set
419     */
420    if ( symlinks == SYM_EXPAND )
421        for (s = *vl; s; s = *++vl) {
422            *vl = dnormalize(s, 1);
423            xfree((ptr_t) s);
424        }
425    vl = nv;
426
427    return (vl);
428}
429
430static Char *
431handleone(str, vl, action)
432    Char   *str, **vl;
433    int     action;
434{
435
436    Char   *cp, **vlp = vl;
437
438    switch (action) {
439    case G_ERROR:
440        setname(short2str(str));
441        blkfree(vl);
442        stderror(ERR_NAME | ERR_AMBIG);
443        break;
444    case G_APPEND:
445        trim(vlp);
446        str = Strsave(*vlp++);
447        do {
448            cp = Strspl(str, STRspace);
449            xfree((ptr_t) str);
450            str = Strspl(cp, *vlp);
451            xfree((ptr_t) cp);
452        }
453        while (*++vlp);
454        blkfree(vl);
455        break;
456    case G_IGNORE:
457        str = Strsave(strip(*vlp));
458        blkfree(vl);
459        break;
460    default:
461        break;
462    }
463    return (str);
464}
465
466static Char **
467libglob(vl)
468    Char  **vl;
469{
470    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
471    glob_t  globv;
472    char   *ptr;
473    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
474
475    if (!vl || !vl[0])
476        return(vl);
477
478    globv.gl_offs = 0;
479    globv.gl_pathv = 0;
480    globv.gl_pathc = 0;
481
482    if (nonomatch)
483        gflgs |= GLOB_NOCHECK;
484
485    do {
486        ptr = short2qstr(*vl);
487        switch (glob(ptr, gflgs, 0, &globv)) {
488        case GLOB_ABEND:
489            globfree(&globv);
490            setname(ptr);
491            stderror(ERR_NAME | ERR_GLOB);
492            /* NOTREACHED */
493        case GLOB_NOSPACE:
494            globfree(&globv);
495            stderror(ERR_NOMEM);
496            /* NOTREACHED */
497        default:
498            break;
499        }
500        if (globv.gl_flags & GLOB_MAGCHAR) {
501            match |= (globv.gl_matchc != 0);
502            magic = 1;
503        }
504        gflgs |= GLOB_APPEND;
505    }
506    while (*++vl);
507    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
508        NULL : blk2short(globv.gl_pathv);
509    globfree(&globv);
510    return (vl);
511}
512
513Char   *
514globone(str, action)
515    Char   *str;
516    int     action;
517{
518
519    Char   *v[2], **vl, **vo;
520    int gflg;
521
522    noglob = adrof(STRnoglob) != 0;
523    gflag = 0;
524    v[0] = str;
525    v[1] = 0;
526    tglob(v);
527    gflg = gflag;
528    if (gflg == G_NONE)
529        return (strip(Strsave(str)));
530
531    if (gflg & G_CSH) {
532        /*
533         * Expand back-quote, tilde and brace
534         */
535        vo = globexpand(v);
536        if (noglob || (gflg & G_GLOB) == 0) {
537            if (vo[0] == NULL) {
538                xfree((ptr_t) vo);
539                return (Strsave(STRNULL));
540            }
541            if (vo[1] != NULL)
542                return (handleone(str, vo, action));
543            else {
544                str = strip(vo[0]);
545                xfree((ptr_t) vo);
546                return (str);
547            }
548        }
549    }
550    else if (noglob || (gflg & G_GLOB) == 0)
551        return (strip(Strsave(str)));
552    else
553        vo = v;
554
555    vl = libglob(vo);
556    if ((gflg & G_CSH) && vl != vo)
557        blkfree(vo);
558    if (vl == NULL) {
559        setname(short2str(str));
560        stderror(ERR_NAME | ERR_NOMATCH);
561    }
562    if (vl[0] == NULL) {
563        xfree((ptr_t) vl);
564        return (Strsave(STRNULL));
565    }
566    if (vl[1])
567        return (handleone(str, vl, action));
568    else {
569        str = strip(*vl);
570        xfree((ptr_t) vl);
571        return (str);
572    }
573}
574
575Char  **
576globall(v)
577    Char  **v;
578{
579    Char  **vl, **vo;
580    int gflg = gflag;
581
582    if (!v || !v[0]) {
583        gargv = saveblk(v);
584        gargc = blklen(gargv);
585        return (gargv);
586    }
587
588    noglob = adrof(STRnoglob) != 0;
589
590    if (gflg & G_CSH)
591        /*
592         * Expand back-quote, tilde and brace
593         */
594        vl = vo = globexpand(v);
595    else
596        vl = vo = saveblk(v);
597
598    if (!noglob && (gflg & G_GLOB)) {
599        vl = libglob(vo);
600        if (vl != vo)
601            blkfree(vo);
602    }
603    else
604        trim(vl);
605
606    gargc = vl ? blklen(vl) : 0;
607    return (gargv = vl);
608}
609
610void
611ginit()
612{
613    gargsiz = GLOBSPACE;
614    gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
615    gargv[0] = 0;
616    gargc = 0;
617}
618
619void
620rscan(t, f)
621    register Char **t;
622    void    (*f) ();
623{
624    register Char *p;
625
626    while ((p = *t++) != '\0')
627        while (*p)
628            (*f) (*p++);
629}
630
631void
632trim(t)
633    register Char **t;
634{
635    register Char *p;
636
637    while ((p = *t++) != '\0')
638        while (*p)
639            *p++ &= TRIM;
640}
641
642void
643tglob(t)
644    register Char **t;
645{
646    register Char *p, *c;
647
648    while ((p = *t++) != '\0') {
649        if (*p == '~' || *p == '=')
650            gflag |= G_CSH;
651        else if (*p == '{' &&
652                 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
653            continue;
654        while ( *(c = p++) ) {
655            /*
656             * eat everything inside the matching backquotes
657             */
658            if (*c == '`') {
659                gflag |= G_CSH;
660                while (*p && *p != '`')
661                    if (*p++ == '\\') {
662                        if (*p)         /* Quoted chars */
663                            p++;
664                        else
665                            break;
666                    }
667                if (*p)                 /* The matching ` */
668                    p++;
669                else
670                    break;
671            }
672            else if (*c == '{')
673                gflag |= G_CSH;
674            else if (isglob(*c))
675                gflag |= G_GLOB;
676            else if (symlinks == SYM_EXPAND &&
677                *p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') )
678                gflag |= G_CSH;
679        }
680    }
681}
682
683/*
684 * Command substitute cp.  If literal, then this is a substitution from a
685 * << redirection, and so we should not crunch blanks and tabs, separating
686 * words only at newlines.
687 */
688Char  **
689dobackp(cp, literal)
690    Char   *cp;
691    bool    literal;
692{
693    register Char *lp, *rp;
694    Char   *ep, word[BUFSIZE];
695
696    if (pargv) {
697#ifdef notdef
698        abort();
699#endif
700        blkfree(pargv);
701    }
702    pargsiz = GLOBSPACE;
703    pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz));
704    pargv[0] = NULL;
705    pargcp = pargs = word;
706    pargc = 0;
707    pnleft = BUFSIZE - 4;
708    for (;;) {
709        for (lp = cp; *lp != '`'; lp++) {
710            if (*lp == 0) {
711                if (pargcp != pargs)
712                    pword();
713                return (pargv);
714            }
715            psave(*lp);
716        }
717        lp++;
718        for (rp = lp; *rp && *rp != '`'; rp++)
719            if (*rp == '\\') {
720                rp++;
721                if (!*rp)
722                    goto oops;
723            }
724        if (!*rp)
725    oops:  stderror(ERR_UNMATCHED, '`');
726        ep = Strsave(lp);
727        ep[rp - lp] = 0;
728        backeval(ep, literal);
729        cp = rp + 1;
730    }
731}
732
733
734static void
735backeval(cp, literal)
736    Char   *cp;
737    bool    literal;
738{
739    register int icnt, c;
740    register Char *ip;
741    struct command faket;
742    bool    hadnl;
743    int     pvec[2], quoted;
744    Char   *fakecom[2], ibuf[BUFSIZE];
745    char    tibuf[BUFSIZE];
746
747    hadnl = 0;
748    icnt = 0;
749    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
750    faket.t_dtyp = NODE_COMMAND;
751    faket.t_dflg = F_BACKQ;
752    faket.t_dlef = 0;
753    faket.t_drit = 0;
754    faket.t_dspr = 0;
755    faket.t_dcom = fakecom;
756    fakecom[0] = STRfakecom1;
757    fakecom[1] = 0;
758
759    /*
760     * We do the psave job to temporarily change the current job so that the
761     * following fork is considered a separate job.  This is so that when
762     * backquotes are used in a builtin function that calls glob the "current
763     * job" is not corrupted.  We only need one level of pushed jobs as long as
764     * we are sure to fork here.
765     */
766    psavejob();
767
768    /*
769     * It would be nicer if we could integrate this redirection more with the
770     * routines in sh.sem.c by doing a fake execute on a builtin function that
771     * was piped out.
772     */
773    mypipe(pvec);
774    if (pfork(&faket, -1) == 0) {
775        struct wordent paraml;
776        struct command *t;
777
778        (void) close(pvec[0]);
779        (void) dmove(pvec[1], 1);
780        (void) dmove(SHDIAG,  2);
781        initdesc();
782        /*
783         * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
784         * posted to comp.bugs.4bsd 12 Sep. 1989.
785         */
786        if (pargv)              /* mg, 21.dec.88 */
787            blkfree(pargv), pargv = 0, pargsiz = 0;
788        /* mg, 21.dec.88 */
789        arginp = cp;
790        while (*cp)
791            *cp++ &= TRIM;
792
793        /*
794         * In the child ``forget'' everything about current aliases or
795         * eval vectors.
796         */
797        alvec = NULL;
798        evalvec = NULL;
799        alvecp = NULL;
800        evalp = NULL;
801        (void) lex(&paraml);
802        if (seterr)
803            stderror(ERR_OLD);
804        alias(&paraml);
805        t = syntax(paraml.next, &paraml, 0);
806        if (seterr)
807            stderror(ERR_OLD);
808        if (t)
809            t->t_dflg |= F_NOFORK;
810#ifdef SIGTSTP
811        (void) sigignore(SIGTSTP);
812#endif
813#ifdef SIGTTIN
814        (void) sigignore(SIGTTIN);
815#endif
816#ifdef SIGTTOU
817        (void) sigignore(SIGTTOU);
818#endif
819        execute(t, -1, NULL, NULL);
820        exitstat();
821    }
822    xfree((ptr_t) cp);
823    (void) close(pvec[1]);
824    c = 0;
825    ip = NULL;
826    do {
827        int     cnt = 0;
828
829        for (;;) {
830            if (icnt == 0) {
831                int     i;
832
833                ip = ibuf;
834                do
835                    icnt = read(pvec[0], tibuf, BUFSIZE);
836                while (icnt == -1 && errno == EINTR);
837                if (icnt <= 0) {
838                    c = -1;
839                    break;
840                }
841                for (i = 0; i < icnt; i++)
842                    ip[i] = (unsigned char) tibuf[i];
843            }
844            if (hadnl)
845                break;
846            --icnt;
847            c = (*ip++ & TRIM);
848            if (c == 0)
849                break;
850            if (c == '\n') {
851                /*
852                 * Continue around the loop one more time, so that we can eat
853                 * the last newline without terminating this word.
854                 */
855                hadnl = 1;
856                continue;
857            }
858            if (!quoted && (c == ' ' || c == '\t'))
859                break;
860            cnt++;
861            psave(c | quoted);
862        }
863        /*
864         * Unless at end-of-file, we will form a new word here if there were
865         * characters in the word, or in any case when we take text literally.
866         * If we didn't make empty words here when literal was set then we
867         * would lose blank lines.
868         */
869        if (c != -1 && (cnt || literal))
870            pword();
871        hadnl = 0;
872    } while (c >= 0);
873    (void) close(pvec[0]);
874    pwait();
875    prestjob();
876}
877
878static void
879psave(c)
880    int    c;
881{
882    if (--pnleft <= 0)
883        stderror(ERR_WTOOLONG);
884    *pargcp++ = c;
885}
886
887static void
888pword()
889{
890    psave(0);
891    if (pargc == pargsiz - 1) {
892        pargsiz += GLOBSPACE;
893        pargv = (Char **) xrealloc((ptr_t) pargv,
894                                   (size_t) (pargsiz * sizeof(Char *)));
895    }
896    pargv[pargc++] = Strsave(pargs);
897    pargv[pargc] = NULL;
898    pargcp = pargs;
899    pnleft = BUFSIZE - 4;
900}
901
902int
903Gmatch(string, pattern)
904    Char *string, *pattern;
905{
906    return Gnmatch(string, pattern, NULL);
907}
908
909int
910Gnmatch(string, pattern, endstr)
911    Char *string, *pattern, **endstr;
912{
913    Char **blk, **p, *tstring = string;
914    int    gpol = 1, gres = 0;
915
916    if (*pattern == '^') {
917        gpol = 0;
918        pattern++;
919    }
920
921    blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *)));
922    blk[0] = Strsave(pattern);
923    blk[1] = NULL;
924
925    expbrace(&blk, NULL, GLOBSPACE);
926
927    if (endstr == NULL)
928        /* Exact matches only */
929        for (p = blk; *p; p++)
930            gres |= pmatch(string, *p, &tstring) == 2 ? 1 : 0;
931    else {
932        /* partial matches */
933        int minc = 0x7fffffff;
934        for (p = blk; *p; p++)
935            if (pmatch(string, *p, &tstring) != 0) {
936                int t = tstring - string;
937                gres |= 1;
938                if (minc == -1 || minc > t)
939                    minc = t;
940            }
941        *endstr = string + minc;
942    }
943
944    blkfree(blk);
945    return(gres == gpol);
946}
947
948/* pmatch():
949 *      Return 2 on exact match,       
950 *      Return 1 on substring match.
951 *      Return 0 on no match.
952 *      *estr will point to the end of the longest exact or substring match.
953 */
954static int
955pmatch(string, pattern, estr)
956    register Char *string, *pattern, **estr;
957{
958    register Char stringc, patternc;
959    int     match, negate_range;
960    Char    rangec, *oestr, *pestr;
961
962    for (;; ++string) {
963        stringc = *string & TRIM;
964        /*
965         * apollo compiler bug: switch (patternc = *pattern++) dies
966         */
967        patternc = *pattern++;
968        switch (patternc) {
969        case 0:
970            *estr = string;
971            return (stringc == 0 ? 2 : 1);
972        case '?':
973            if (stringc == 0)
974                return (0);
975            *estr = string;
976            break;
977        case '*':
978            if (!*pattern) {
979                while (*string) string++;
980                *estr = string;
981                return (2);
982            }
983            oestr = *estr;
984            pestr = NULL;
985
986            do {
987                switch(pmatch(string, pattern, estr)) {
988                case 0:
989                    break;
990                case 1:
991                    pestr = *estr;
992                    break;
993                case 2:
994                    return 2;
995                default:
996                    abort();    /* Cannot happen */
997                }
998                *estr = string;
999            }
1000            while (*string++);
1001
1002            if (pestr) {
1003                *estr = pestr;
1004                return 1;
1005            }
1006            else {
1007                *estr = oestr;
1008                return 0;
1009            }
1010
1011        case '[':
1012            match = 0;
1013            if ((negate_range = (*pattern == '^')) != 0)
1014                pattern++;
1015            while ((rangec = *pattern++) != '\0') {
1016                if (rangec == ']')
1017                    break;
1018                if (match)
1019                    continue;
1020                if (rangec == '-' && *(pattern-2) != '[' && *pattern  != ']') {
1021                    match = (stringc <= (*pattern & TRIM) &&
1022                              (*(pattern-2) & TRIM) <= stringc);
1023                    pattern++;
1024                }
1025                else
1026                    match = (stringc == (rangec & TRIM));
1027            }
1028            if (rangec == 0)
1029                stderror(ERR_NAME | ERR_MISSING, ']');
1030            if (match == negate_range)
1031                return (0);
1032            *estr = string;
1033            break;
1034        default:
1035            if ((patternc & TRIM) != stringc)
1036                return (0);
1037            *estr = string;
1038            break;
1039        }
1040    }
1041}
1042
1043void
1044Gcat(s1, s2)
1045    Char   *s1, *s2;
1046{
1047    register Char *p, *q;
1048    int     n;
1049
1050    for (p = s1; *p++;)
1051        continue;
1052    for (q = s2; *q++;)
1053        continue;
1054    n = (p - s1) + (q - s2) - 1;
1055    if (++gargc >= gargsiz) {
1056        gargsiz += GLOBSPACE;
1057        gargv = (Char **) xrealloc((ptr_t) gargv,
1058                                   (size_t) (gargsiz * sizeof(Char *)));
1059    }
1060    gargv[gargc] = 0;
1061    p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char)));
1062    for (q = s1; (*p++ = *q++) != '\0';)
1063        continue;
1064    for (p--, q = s2; (*p++ = *q++) != '\0';)
1065        continue;
1066}
1067
1068#ifdef FILEC
1069int
1070sortscmp(a, b)
1071    register Char **a, **b;
1072{
1073    if (!a)                     /* check for NULL */
1074        return (b ? 1 : 0);
1075    if (!b)
1076        return (-1);
1077
1078    if (!*a)                    /* check for NULL */
1079        return (*b ? 1 : 0);
1080    if (!*b)
1081        return (-1);
1082
1083    return (int) collate(a, b);
1084}
1085
1086#endif
Note: See TracBrowser for help on using the repository browser.