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 /* 116 * Do p and q point at equal utf codes 117 */ 118 int 119 equtf(uchar *p, uchar *q) 120 { 121 Rune pr, qr; 122 if(*p!=*q) 123 return 0; 124 125 chartorune(&pr, (char*)p); 126 chartorune(&qr, (char*)q); 127 return pr == qr; 128 } 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 uchar* 136 nextutf(uchar *p) 137 { 138 Rune dummy; 139 return p + chartorune(&dummy, (char*)p); 140 } 141 142 /* 143 * Convert the utf code at *p to a unicode value 144 */ 145 146 int 147 unicode(uchar *p) 148 { 149 Rune r; 150 151 chartorune(&r, (char*)p); 152 return r; 153 } 154 155 /* 156 * Does the string s match the pattern p 157 * . and .. are only matched by patterns starting with . 158 * * matches any sequence of characters 159 * ? matches any single character 160 * [...] matches the enclosed list of characters 161 */ 162 163 int 164 matchfn(void *as, void *ap) 165 { 166 uchar *s = as, *p = ap; 167 168 if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') 169 return 0; 170 return match(s, p, '/'); 171 } 172 173 int 174 match(void *as, void *ap, int stop) 175 { 176 int compl, hit, lo, hi, t, c; 177 uchar *s = as, *p = ap; 178 179 for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){ 180 if(*p!=GLOB){ 181 if(!equtf(p, s)) return 0; 182 } 183 else switch(*++p){ 184 case GLOB: 185 if(*s!=GLOB) 186 return 0; 187 break; 188 case '*': 189 for(;;){ 190 if(match(s, nextutf(p), stop)) return 1; 191 if(!*s) 192 break; 193 s = nextutf(s); 194 } 195 return 0; 196 case '?': 197 if(*s=='\0') 198 return 0; 199 break; 200 case '[': 201 if(*s=='\0') 202 return 0; 203 c = unicode(s); 204 p++; 205 compl=*p=='~'; 206 if(compl) 207 p++; 208 hit = 0; 209 while(*p!=']'){ 210 if(*p=='\0') 211 return 0; /* syntax error */ 212 lo = unicode(p); 213 p = nextutf(p); 214 if(*p!='-') 215 hi = lo; 216 else{ 217 p++; 218 if(*p=='\0') 219 return 0; /* syntax error */ 220 hi = unicode(p); 221 p = nextutf(p); 222 if(hi<lo){ t = lo; lo = hi; hi = t; } 223 } 224 if(lo<=c && c<=hi) 225 hit = 1; 226 } 227 if(compl) 228 hit=!hit; 229 if(!hit) 230 return 0; 231 break; 232 } 233 } 234 return *s=='\0'; 235 } 236 237 void 238 globlist1(word *gl) 239 { 240 if(gl){ 241 globlist1(gl->next); 242 glob(gl->word); 243 } 244 } 245 246 void 247 globlist(void) 248 { 249 word *a; 250 globv = 0; 251 globlist1(runq->argv->words); 252 poplist(); 253 pushlist(); 254 if(globv){ 255 for(a = globv;a->next;a = a->next); 256 a->next = runq->argv->words; 257 runq->argv->words = globv; 258 } 259 } 260