| #include "stdinc.h" | 
 | #include "vac.h" | 
 | #include "dat.h" | 
 | #include "fns.h" | 
 | #include "error.h" | 
 |  | 
 | // Convert globbish pattern to regular expression | 
 | // The wildcards are | 
 | // | 
 | //	*	any non-slash characters | 
 | //	...	any characters including / | 
 | //	?	any single character except / | 
 | //	[a-z]	character class | 
 | //	[~a-z]	negated character class | 
 | // | 
 |  | 
 | Reprog* | 
 | glob2regexp(char *glob) | 
 | { | 
 | 	char *s, *p, *w; | 
 | 	Reprog *re; | 
 | 	int boe;	// beginning of path element | 
 |  | 
 | 	s = malloc(20*(strlen(glob)+1)); | 
 | 	if(s == nil) | 
 | 		return nil; | 
 | 	w = s; | 
 | 	boe = 1; | 
 | 	*w++ = '^'; | 
 | 	*w++ = '('; | 
 | 	for(p=glob; *p; p++){ | 
 | 		if(p[0] == '.' && p[1] == '.' && p[2] == '.'){ | 
 | 			strcpy(w, ".*"); | 
 | 			w += strlen(w); | 
 | 			p += 3-1; | 
 | 			boe = 0; | 
 | 			continue; | 
 | 		} | 
 | 		if(p[0] == '*'){ | 
 | 			if(boe) | 
 | 				strcpy(w, "([^./][^/]*)?"); | 
 | 			else | 
 | 				strcpy(w, "[^/]*"); | 
 | 			w += strlen(w); | 
 | 			boe = 0; | 
 | 			continue; | 
 | 		} | 
 | 		if(p[0] == '?'){ | 
 | 			if(boe) | 
 | 				strcpy(w, "[^./]"); | 
 | 			else | 
 | 				strcpy(w, "[^/]"); | 
 | 			w += strlen(w); | 
 | 			boe = 0; | 
 | 			continue; | 
 | 		} | 
 | 		if(p[0] == '['){ | 
 | 			*w++ = '['; | 
 | 			if(*++p == '~'){ | 
 | 				*w++ = '^'; | 
 | 				p++; | 
 | 			} | 
 | 			while(*p != ']'){ | 
 | 				if(*p == '/') | 
 | 					goto syntax; | 
 | 				if(*p == '^' || *p == '\\') | 
 | 					*w++ = '\\'; | 
 | 				*w++ = *p++; | 
 | 			} | 
 | 			*w++ = ']'; | 
 | 			boe = 0; | 
 | 			continue; | 
 | 		} | 
 | 		if(strchr("()|^$[]*?+\\.", *p)){ | 
 | 			*w++ = '\\'; | 
 | 			*w++ = *p; | 
 | 			boe = 0; | 
 | 			continue; | 
 | 		} | 
 | 		if(*p == '/'){ | 
 | 			*w++ = '/'; | 
 | 			boe = 1; | 
 | 			continue; | 
 | 		} | 
 | 		*w++ = *p; | 
 | 		boe = 0; | 
 | 		continue; | 
 | 	} | 
 | 	*w++ = ')'; | 
 | 	*w++ = '$'; | 
 | 	*w = 0; | 
 | 	 | 
 | 	re = regcomp(s); | 
 | 	if(re == nil){ | 
 | 	syntax: | 
 | 		free(s); | 
 | 		werrstr("glob syntax error"); | 
 | 		return nil; | 
 | 	} | 
 | 	free(s); | 
 | 	return re; | 
 | } | 
 |  | 
 | typedef struct Pattern Pattern; | 
 | struct Pattern | 
 | { | 
 | 	Reprog *re; | 
 | 	int include; | 
 | }; | 
 |  | 
 | Pattern *pattern; | 
 | int npattern; | 
 |  | 
 | void | 
 | loadexcludefile(char *file) | 
 | { | 
 | 	Biobuf *b; | 
 | 	char *p, *q; | 
 | 	int n, inc; | 
 | 	Reprog *re; | 
 |  | 
 | 	if((b = Bopen(file, OREAD)) == nil) | 
 | 		sysfatal("open %s: %r", file); | 
 | 	for(n=1; (p=Brdstr(b, '\n', 1)) != nil; free(p), n++){ | 
 | 		q = p+strlen(p); | 
 | 		while(q > p && isspace((uchar)*(q-1))) | 
 | 			*--q = 0; | 
 | 		switch(p[0]){ | 
 | 		case '\0': | 
 | 		case '#': | 
 | 			continue; | 
 | 		} | 
 | 		 | 
 | 		inc = 0; | 
 | 		if(strncmp(p, "include ", 8) == 0){ | 
 | 			inc = 1; | 
 | 		}else if(strncmp(p, "exclude ", 8) == 0){ | 
 | 			inc = 0; | 
 | 		}else | 
 | 			sysfatal("%s:%d: line does not begin with include or exclude", file, n); | 
 |  | 
 | 		if(strchr(p+8, ' ')) | 
 | 			fprint(2, "%s:%d: warning: space in pattern\n", file, n); | 
 |  | 
 | 		if((re = glob2regexp(p+8)) == nil) | 
 | 			sysfatal("%s:%d: bad glob pattern", file, n); | 
 |  | 
 | 		pattern = vtrealloc(pattern, (npattern+1)*sizeof pattern[0]); | 
 | 		pattern[npattern].re = re; | 
 | 		pattern[npattern].include = inc; | 
 | 		npattern++; | 
 | 	} | 
 | 	Bterm(b); | 
 | } | 
 |  | 
 | void | 
 | excludepattern(char *p) | 
 | { | 
 | 	Reprog *re; | 
 | 	 | 
 | 	if((re = glob2regexp(p)) == nil) | 
 | 		sysfatal("bad glob pattern %s", p); | 
 |  | 
 | 	pattern = vtrealloc(pattern, (npattern+1)*sizeof pattern[0]); | 
 | 	pattern[npattern].re = re; | 
 | 	pattern[npattern].include = 0; | 
 | 	npattern++; | 
 | } | 
 |  | 
 | int | 
 | includefile(char *file) | 
 | { | 
 | 	Pattern *p, *ep; | 
 | 	 | 
 | 	for(p=pattern, ep=p+npattern; p<ep; p++) | 
 | 		if(regexec(p->re, file, nil, 0)) | 
 | 			return p->include; | 
 | 	return 1; | 
 | } | 
 |  |