glob.c (2991B)
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 }