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