glob.c (4858B)
1 #include "rc.h" 2 #include "exec.h" 3 #include "fns.h" 4 char *globname; 5 struct word *globv; 6 /* 7 * delete all the GLOB marks from s, in place 8 */ 9 10 void 11 deglob(char *s) 12 { 13 char *t = s; 14 do{ 15 if(*t==GLOB) 16 t++; 17 *s++=*t; 18 }while(*t++); 19 } 20 21 int 22 globcmp(const void *s, const void *t) 23 { 24 return strcmp(*(char**)s, *(char**)t); 25 } 26 27 void 28 globsort(word *left, word *right) 29 { 30 char **list; 31 word *a; 32 int n = 0; 33 for(a = left;a!=right;a = a->next) n++; 34 list = (char **)emalloc(n*sizeof(char *)); 35 for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word; 36 qsort((void *)list, n, sizeof(void *), globcmp); 37 for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n]; 38 efree((char *)list); 39 } 40 /* 41 * Push names prefixed by globname and suffixed by a match of p onto the astack. 42 * namep points to the end of the prefix in globname. 43 */ 44 45 void 46 globdir(char *p, char *namep) 47 { 48 char *t, *newp; 49 int f; 50 /* scan the pattern looking for a component with a metacharacter in it */ 51 if(*p=='\0'){ 52 globv = newword(globname, globv); 53 return; 54 } 55 t = namep; 56 newp = p; 57 while(*newp){ 58 if(*newp==GLOB) 59 break; 60 *t=*newp++; 61 if(*t++=='/'){ 62 namep = t; 63 p = newp; 64 } 65 } 66 /* If we ran out of pattern, append the name if accessible */ 67 if(*newp=='\0'){ 68 *t='\0'; 69 if(access(globname, 0)==0) 70 globv = newword(globname, globv); 71 return; 72 } 73 /* read the directory and recur for any entry that matches */ 74 *namep='\0'; 75 if((f = Opendir(globname[0]?globname:"."))<0) return; 76 while(*newp!='/' && *newp!='\0') newp++; 77 while(Readdir(f, namep, *newp=='/')){ 78 if(matchfn(namep, p)){ 79 for(t = namep;*t;t++); 80 globdir(newp, t); 81 } 82 } 83 Closedir(f); 84 } 85 /* 86 * Push all file names matched by p on the current thread's stack. 87 * If there are no matches, the list consists of p. 88 */ 89 90 void 91 glob(char *p) 92 { 93 word *svglobv = globv; 94 int globlen = Globsize(p); 95 if(!globlen){ 96 deglob(p); 97 globv = newword(p, globv); 98 return; 99 } 100 globname = emalloc(globlen); 101 globname[0]='\0'; 102 globdir(p, globname); 103 efree(globname); 104 if(svglobv==globv){ 105 deglob(p); 106 globv = newword(p, globv); 107 } 108 else 109 globsort(globv, svglobv); 110 } 111 /* 112 * Do p and q point at equal utf codes 113 */ 114 115 int 116 equtf(char *p, char *q) 117 { 118 if(*p!=*q) 119 return 0; 120 if(twobyte(*p)) return p[1]==q[1]; 121 if(threebyte(*p)){ 122 if(p[1]!=q[1]) 123 return 0; 124 if(p[1]=='\0') 125 return 1; /* broken code at end of string! */ 126 return p[2]==q[2]; 127 } 128 if(fourbyte(*p)){ 129 if(p[1]!=q[1]) 130 return 0; 131 if(p[1]=='\0') 132 return 1; 133 if(p[2]!=q[2]) 134 return 0; 135 if(p[2]=='\0') 136 return 1; 137 return p[3]==q[3]; 138 } 139 return 1; 140 } 141 /* 142 * Return a pointer to the next utf code in the string, 143 * not jumping past nuls in broken utf codes! 144 */ 145 146 char* 147 nextutf(char *p) 148 { 149 if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; 150 if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; 151 if(fourbyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p[3]=='\0'?p+3:p+4; 152 return p+1; 153 } 154 /* 155 * Convert the utf code at *p to a unicode value 156 */ 157 158 int 159 unicode(char *p) 160 { 161 int u=*p&0xff; 162 if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f); 163 if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); 164 if(fourbyte(u)) return (u<<18)|((p[1]&0x3f)<<12)|((p[2]&0x3f)<<6)|(p[3]&0x3f); 165 return u; 166 } 167 /* 168 * Does the string s match the pattern p 169 * . and .. are only matched by patterns starting with . 170 * * matches any sequence of characters 171 * ? matches any single character 172 * [...] matches the enclosed list of characters 173 */ 174 175 int 176 matchfn(char *s, char *p) 177 { 178 if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') 179 return 0; 180 return match(s, p, '/'); 181 } 182 183 int 184 match(char *s, char *p, int stop) 185 { 186 int compl, hit, lo, hi, t, c; 187 for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){ 188 if(*p!=GLOB){ 189 if(!equtf(p, s)) return 0; 190 } 191 else switch(*++p){ 192 case GLOB: 193 if(*s!=GLOB) 194 return 0; 195 break; 196 case '*': 197 for(;;){ 198 if(match(s, nextutf(p), stop)) return 1; 199 if(!*s) 200 break; 201 s = nextutf(s); 202 } 203 return 0; 204 case '?': 205 if(*s=='\0') 206 return 0; 207 break; 208 case '[': 209 if(*s=='\0') 210 return 0; 211 c = unicode(s); 212 p++; 213 compl=*p=='~'; 214 if(compl) 215 p++; 216 hit = 0; 217 while(*p!=']'){ 218 if(*p=='\0') 219 return 0; /* syntax error */ 220 lo = unicode(p); 221 p = nextutf(p); 222 if(*p!='-') 223 hi = lo; 224 else{ 225 p++; 226 if(*p=='\0') 227 return 0; /* syntax error */ 228 hi = unicode(p); 229 p = nextutf(p); 230 if(hi<lo){ t = lo; lo = hi; hi = t; } 231 } 232 if(lo<=c && c<=hi) 233 hit = 1; 234 } 235 if(compl) 236 hit=!hit; 237 if(!hit) 238 return 0; 239 break; 240 } 241 } 242 return *s=='\0'; 243 } 244 245 void 246 globlist1(word *gl) 247 { 248 if(gl){ 249 globlist1(gl->next); 250 glob(gl->word); 251 } 252 } 253 254 void 255 globlist(void) 256 { 257 word *a; 258 globv = 0; 259 globlist1(runq->argv->words); 260 poplist(); 261 pushlist(); 262 if(globv){ 263 for(a = globv;a->next;a = a->next); 264 a->next = runq->argv->words; 265 runq->argv->words = globv; 266 } 267 }