aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/glob.c
blob: 9d88b5953d55c60b91e9199ff78ab20ec8f7236d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "rc.h"

/* removes glob marks in place */
void
deglob(char *s)
{
    char *t = s;
    do{
        if(*t==GLOB)
            t++;
        *s++=*t;
    }while(*t++);
}

int
match(char *s, char *p,  int stop)
{
    rune rs, rp, lo, hi;
    int neg, hit;

    utf8·decode(p, &rp), utf8·decode(s, &rs);
    for(; *p && *p != stop; s+=utf8·decode(s,&rs),p+=utf8·decode(p,&rp)){
        /* fast path: normal character */
        if(*p != GLOB){
            if(rp != rs)
                return 0;
            continue;
        }

        /* unglob */
        switch(*++p){
        case GLOB:
            if(*s != GLOB)
                return 0;
            break;
        case '*':
            for(;;){
                p += utf8·decode(p, &rp);
                if(match(s, p, stop))
                    return 1;
                s += utf8·decode(s, &rs);
            }
            return 0;

        case '?':
            if(*s == 0)
                return 0;
            break;

        case '[':
            if(*s==0)
                return 0;
            if((neg=*++p=='~'))
                p++;
            hit = 0;
            while(*p != ']'){
                if(*p==0)
                    return 0; /* syntax error */
                p += utf8·decode(p, &lo);
                if(*p != '-')
                   hi = lo;
                else{
                    if(*++p == 0)
                        return 0; /* syntax error */
                    p += utf8·decode(p, &hi);
                    if(hi < lo)
                        rp=lo, lo=hi, hi=rp;
                }

                if(lo <= rs && rs <= hi)
                    hit = 1;
            }
            if(neg)
                hit=!hit;
            if(!hit)
                return 0;
            break;
        }
    }

    return *s == 0;
}