| glob.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
| git clone git://git.suckless.org/9base | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| 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… | |
| 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… | |
| 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; /* synt… | |
| 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; /* synt… | |
| 215 hi = unicode(p); | |
| 216 p = nextutf(p); | |
| 217 if(hi<lo){ t = lo; lo = hi; hi =… | |
| 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 } |