|  | #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; | 
|  | } | 
|  |  |