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