glob.c (4540B)
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 return 1; 129 } 130 /* 131 * Return a pointer to the next utf code in the string, 132 * not jumping past nuls in broken utf codes! 133 */ 134 135 char* 136 nextutf(char *p) 137 { 138 if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; 139 if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; 140 return p+1; 141 } 142 /* 143 * Convert the utf code at *p to a unicode value 144 */ 145 146 int 147 unicode(char *p) 148 { 149 int u=*p&0xff; 150 if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f); 151 if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); 152 return u; 153 } 154 /* 155 * Does the string s match the pattern p 156 * . and .. are only matched by patterns starting with . 157 * * matches any sequence of characters 158 * ? matches any single character 159 * [...] matches the enclosed list of characters 160 */ 161 162 int 163 matchfn(char *s, char *p) 164 { 165 if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') 166 return 0; 167 return match(s, p, '/'); 168 } 169 170 int 171 match(char *s, char *p, int stop) 172 { 173 int compl, hit, lo, hi, t, c; 174 for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){ 175 if(*p!=GLOB){ 176 if(!equtf(p, s)) return 0; 177 } 178 else switch(*++p){ 179 case GLOB: 180 if(*s!=GLOB) 181 return 0; 182 break; 183 case '*': 184 for(;;){ 185 if(match(s, nextutf(p), stop)) return 1; 186 if(!*s) 187 break; 188 s = nextutf(s); 189 } 190 return 0; 191 case '?': 192 if(*s=='\0') 193 return 0; 194 break; 195 case '[': 196 if(*s=='\0') 197 return 0; 198 c = unicode(s); 199 p++; 200 compl=*p=='~'; 201 if(compl) 202 p++; 203 hit = 0; 204 while(*p!=']'){ 205 if(*p=='\0') 206 return 0; /* syntax error */ 207 lo = unicode(p); 208 p = nextutf(p); 209 if(*p!='-') 210 hi = lo; 211 else{ 212 p++; 213 if(*p=='\0') 214 return 0; /* syntax error */ 215 hi = unicode(p); 216 p = nextutf(p); 217 if(hi<lo){ t = lo; lo = hi; hi = t; } 218 } 219 if(lo<=c && c<=hi) 220 hit = 1; 221 } 222 if(compl) 223 hit=!hit; 224 if(!hit) 225 return 0; 226 break; 227 } 228 } 229 return *s=='\0'; 230 } 231 232 void 233 globlist1(word *gl) 234 { 235 if(gl){ 236 globlist1(gl->next); 237 glob(gl->word); 238 } 239 } 240 241 void 242 globlist(void) 243 { 244 word *a; 245 globv = 0; 246 globlist1(runq->argv->words); 247 poplist(); 248 pushlist(); 249 if(globv){ 250 for(a = globv;a->next;a = a->next); 251 a->next = runq->argv->words; 252 runq->argv->words = globv; 253 } 254 }