]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vac/glob.c
snoopy(8): avoid extra spaces in dhcp filter output
[plan9front.git] / sys / src / cmd / vac / glob.c
1 #include "stdinc.h"
2 #include "vac.h"
3 #include "dat.h"
4 #include "fns.h"
5 #include "error.h"
6
7 // Convert globbish pattern to regular expression
8 // The wildcards are
9 //
10 //      *       any non-slash characters
11 //      ...     any characters including /
12 //      ?       any single character except /
13 //      [a-z]   character class
14 //      [~a-z]  negated character class
15 //
16
17 Reprog*
18 glob2regexp(char *glob)
19 {
20         char *s, *p, *w;
21         Reprog *re;
22         int boe;        // beginning of path element
23
24         s = malloc(20*(strlen(glob)+1));
25         if(s == nil)
26                 return nil;
27         w = s;
28         boe = 1;
29         *w++ = '^';
30         *w++ = '(';
31         for(p=glob; *p; p++){
32                 if(p[0] == '.' && p[1] == '.' && p[2] == '.'){
33                         strcpy(w, ".*");
34                         w += strlen(w);
35                         p += 3-1;
36                         boe = 0;
37                         continue;
38                 }
39                 if(p[0] == '*'){
40                         if(boe)
41                                 strcpy(w, "([^./][^/]*)?");
42                         else
43                                 strcpy(w, "[^/]*");
44                         w += strlen(w);
45                         boe = 0;
46                         continue;
47                 }
48                 if(p[0] == '?'){
49                         if(boe)
50                                 strcpy(w, "[^./]");
51                         else
52                                 strcpy(w, "[^/]");
53                         w += strlen(w);
54                         boe = 0;
55                         continue;
56                 }
57                 if(p[0] == '['){
58                         *w++ = '[';
59                         if(*++p == '~'){
60                                 *w++ = '^';
61                                 p++;
62                         }
63                         while(*p != ']'){
64                                 if(*p == '/')
65                                         goto syntax;
66                                 if(*p == '^' || *p == '\\')
67                                         *w++ = '\\';
68                                 *w++ = *p++;
69                         }
70                         *w++ = ']';
71                         boe = 0;
72                         continue;
73                 }
74                 if(strchr("()|^$[]*?+\\.", *p)){
75                         *w++ = '\\';
76                         *w++ = *p;
77                         boe = 0;
78                         continue;
79                 }
80                 if(*p == '/'){
81                         *w++ = '/';
82                         boe = 1;
83                         continue;
84                 }
85                 *w++ = *p;
86                 boe = 0;
87                 continue;
88         }
89         *w++ = ')';
90         *w++ = '$';
91         *w = 0;
92         
93         re = regcomp(s);
94         if(re == nil){
95         syntax:
96                 free(s);
97                 werrstr("glob syntax error");
98                 return nil;
99         }
100         free(s);
101         return re;
102 }
103
104 typedef struct Pattern Pattern;
105 struct Pattern
106 {
107         Reprog *re;
108         int include;
109 };
110
111 Pattern *pattern;
112 int npattern;
113
114 void
115 loadexcludefile(char *file)
116 {
117         Biobuf *b;
118         char *p, *q;
119         int n, inc;
120         Reprog *re;
121
122         if((b = Bopen(file, OREAD)) == nil)
123                 sysfatal("open %s: %r", file);
124         for(n=1; (p=Brdstr(b, '\n', 1)) != nil; free(p), n++){
125                 q = p+strlen(p);
126                 while(q > p && isspace((uchar)*(q-1)))
127                         *--q = 0;
128                 switch(p[0]){
129                 case '\0':
130                 case '#':
131                         continue;
132                 }
133                 
134                 inc = 0;
135                 if(strncmp(p, "include ", 8) == 0){
136                         inc = 1;
137                 }else if(strncmp(p, "exclude ", 8) == 0){
138                         inc = 0;
139                 }else
140                         sysfatal("%s:%d: line does not begin with include or exclude", file, n);
141
142                 if(strchr(p+8, ' '))
143                         fprint(2, "%s:%d: warning: space in pattern\n", file, n);
144
145                 if((re = glob2regexp(p+8)) == nil)
146                         sysfatal("%s:%d: bad glob pattern", file, n);
147
148                 pattern = vtrealloc(pattern, (npattern+1)*sizeof pattern[0]);
149                 pattern[npattern].re = re;
150                 pattern[npattern].include = inc;
151                 npattern++;
152         }
153         Bterm(b);
154 }
155
156 void
157 excludepattern(char *p)
158 {
159         Reprog *re;
160         
161         if((re = glob2regexp(p)) == nil)
162                 sysfatal("bad glob pattern %s", p);
163
164         pattern = vtrealloc(pattern, (npattern+1)*sizeof pattern[0]);
165         pattern[npattern].re = re;
166         pattern[npattern].include = 0;
167         npattern++;
168 }
169
170 int
171 includefile(char *file)
172 {
173         Pattern *p, *ep;
174         
175         for(p=pattern, ep=p+npattern; p<ep; p++)
176                 if(regexec(p->re, file, nil, 0))
177                         return p->include;
178         return 1;
179 }
180