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 } |