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