Commit | Line | Data |
---|---|---|
dbf02a84 WJ |
1 | /* |
2 | * | |
3 | * glob.c - filename generation | |
4 | * | |
5 | * This file is part of zsh, the Z shell. | |
6 | * | |
7 | * This software is Copyright 1992 by Paul Falstad | |
8 | * | |
9 | * Permission is hereby granted to copy, reproduce, redistribute or otherwise | |
10 | * use this software as long as: there is no monetary profit gained | |
11 | * specifically from the use or reproduction of this software, it is not | |
12 | * sold, rented, traded or otherwise marketed, and this copyright notice is | |
13 | * included prominently in any copy made. | |
14 | * | |
15 | * The author make no claims as to the fitness or correctness of this software | |
16 | * for any use whatsoever, and it is provided as is. Any use of this software | |
17 | * is at the user's own risk. | |
18 | * | |
19 | */ | |
20 | ||
21 | #include "zsh.h" | |
22 | ||
23 | #ifdef __hpux | |
24 | #include <ndir.h> | |
25 | #else | |
26 | #ifdef SYSV | |
27 | #define direct dirent | |
28 | #else | |
29 | #include <sys/dir.h> | |
30 | #endif | |
31 | #endif | |
32 | #include <sys/errno.h> | |
33 | ||
34 | #define exists(X) (access(X,0) == 0 || readlink(X,NULL,0) == 0) | |
35 | ||
36 | static int mode; /* != 0 if we are parsing glob patterns */ | |
37 | static int pathpos; /* position in pathbuf */ | |
38 | static int matchsz; /* size of matchbuf */ | |
39 | static int matchct; /* number of matches found */ | |
40 | static char pathbuf[MAXPATHLEN]; /* pathname buffer */ | |
41 | static char **matchbuf; /* array of matches */ | |
42 | static char **matchptr; /* &matchbuf[matchct] */ | |
43 | static Comp exclude; /* pattern to exclude */ | |
44 | ||
45 | /* max # of qualifiers */ | |
46 | ||
47 | #define QUALCT 16 | |
48 | ||
49 | static int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long)); | |
50 | static long qualdata[QUALCT]; | |
51 | static int qualsense[QUALCT]; | |
52 | static int qualct; | |
53 | static int gf_nullglob,gf_markdirs,gf_noglobdots; | |
54 | ||
55 | /* pathname component in filename patterns */ | |
56 | ||
57 | struct complist { | |
58 | Complist next; | |
59 | Comp comp; | |
60 | int closure; /* 1 if this is a (foo/)# */ | |
61 | }; | |
62 | struct comp { | |
63 | Comp left,right,next; | |
64 | char *str; | |
65 | int closure,last; | |
66 | }; | |
67 | ||
68 | void glob(list,np) /**/ | |
69 | Lklist list;Lknode *np; | |
70 | { | |
71 | Lknode node = prevnode(*np); | |
72 | Lknode next = nextnode(*np); | |
73 | int sl; /* length of the pattern */ | |
74 | char *ostr; /* the pattern before the parser chops it up */ | |
75 | Complist q; /* pattern after parsing */ | |
76 | char *str = getdata(*np); /* the pattern */ | |
77 | ||
78 | sl = strlen(str); | |
79 | ostr = strdup(str); | |
80 | uremnode(list,*np); | |
81 | qualct = 0; | |
82 | gf_nullglob = isset(NULLGLOB); | |
83 | gf_markdirs = isset(MARKDIRS); | |
84 | gf_noglobdots = unset(GLOBDOTS); | |
85 | if (str[sl-1] == Outpar) /* check for qualifiers */ | |
86 | { | |
87 | char *s; | |
88 | int sense = 0; | |
89 | long data; | |
90 | int (*func) DCLPROTO((struct stat *,long)); | |
91 | ||
92 | for (s = str+sl-2; s != str; s--) | |
93 | if (*s == Bar || *s == Outpar || *s == Inpar) | |
94 | break; | |
95 | if (*s == Inpar) | |
96 | { | |
97 | *s++ = '\0'; | |
98 | func = NULL; | |
99 | while (*s != Outpar) | |
100 | { | |
101 | func = NULL; | |
102 | if (idigit(*s)) | |
103 | { | |
104 | func = qualflags; | |
105 | data = 0; | |
106 | while (idigit(*s)) | |
107 | data = data*010+(*s++-'0'); | |
108 | } | |
109 | else switch ((int)(unsigned char)(*s++)) | |
110 | { | |
111 | case (int)(unsigned char)Hat: case '^': sense = 1-sense; break; | |
112 | #ifdef S_IFLNK | |
113 | case '@': func = qualmode; data = S_IFLNK; break; | |
114 | #endif | |
115 | #ifdef S_IFSOCK | |
116 | case '=': func = qualmode; data = S_IFSOCK; break; | |
117 | #endif | |
118 | #ifdef S_IFIFO | |
119 | case 'p': func = qualmode; data = S_IFIFO; break; | |
120 | #endif | |
121 | case '/': func = qualmode; data = S_IFDIR; break; | |
122 | case '.': func = qualmode; data = S_IFREG; break; | |
123 | case '%': func = qualisdev; break; | |
124 | case (int)(unsigned char)Star: func = qualiscom; break; | |
125 | case 'R': func = qualflags; data = 0004; break; | |
126 | case 'W': func = qualflags; data = 0002; break; | |
127 | case 'X': func = qualflags; data = 0001; break; | |
128 | case 'r': func = qualflags; data = 0400; break; | |
129 | case 'w': func = qualflags; data = 0200; break; | |
130 | case 'x': func = qualflags; data = 0100; break; | |
131 | case 's': func = qualflags; data = 04000; break; | |
132 | case 'S': func = qualflags; data = 02000; break; | |
133 | case 'd': func = qualdev; data = qgetnum(&s); break; | |
134 | case 'l': func = qualnlink; data = qgetnum(&s); break; | |
135 | case 'U': func = qualuid; data = geteuid(); break; | |
136 | case 'G': func = qualgid; data = getegid(); break; | |
137 | case 'u': func = qualuid; data = qgetnum(&s); break; | |
138 | case 'g': func = qualgid; data = qgetnum(&s); break; | |
139 | case 'M': gf_markdirs = !sense; break; | |
140 | case 'N': gf_nullglob = !sense; break; | |
141 | case 'D': gf_noglobdots = sense; break; | |
142 | default: zerr("unknown file attribute",NULL,0); return; | |
143 | } | |
144 | if (func) | |
145 | { | |
146 | if (qualct == QUALCT-1) | |
147 | { | |
148 | zerr("too many qualifiers",NULL,0); | |
149 | return; | |
150 | } | |
151 | qualfuncs[qualct] = func; | |
152 | qualsense[qualct] = sense; | |
153 | qualdata[qualct] = data; | |
154 | qualct++; | |
155 | } | |
156 | if (errflag) | |
157 | return; | |
158 | } | |
159 | } | |
160 | } | |
161 | else if ((str[sl-1] == '/') && !((str[sl-2] == Star)&& | |
162 | (str[sl-3] == Star)&&(str[sl-4] == Star)&& | |
163 | (str[sl-5]==Star))) /* foo/ == foo(/) */ | |
164 | { | |
165 | str[sl-1] = '\0'; | |
166 | qualfuncs[0] = qualmode; | |
167 | qualdata[0] = S_IFDIR; | |
168 | qualsense[0] = 0; | |
169 | qualct = 1; | |
170 | } | |
171 | qualfuncs[qualct] = NULL; | |
172 | if (*str == '/') /* pattern has absolute path */ | |
173 | { | |
174 | str++; | |
175 | pathbuf[0] = '/'; | |
176 | pathbuf[pathpos = 1] = '\0'; | |
177 | } | |
178 | else /* pattern is relative to pwd */ | |
179 | pathbuf[pathpos = 0] = '\0'; | |
180 | q = parsepat(str); | |
181 | if (!q || errflag) /* if parsing failed */ | |
182 | { | |
183 | if (isset(NOBADPATTERN)) | |
184 | { | |
185 | insnode(list,node,ostr); | |
186 | return; | |
187 | } | |
188 | errflag = 0; | |
189 | zerr("bad pattern: %s",ostr,0); | |
190 | return; | |
191 | } | |
192 | matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *)); | |
193 | matchct = 0; | |
194 | scanner(q); /* do the globbing */ | |
195 | if (matchct) | |
196 | badcshglob |= 2; | |
197 | else if (!gf_nullglob) | |
198 | if (isset(CSHNULLGLOB)) { | |
199 | badcshglob |= 1; | |
200 | } else if (unset(NONOMATCH)) { | |
201 | zerr("no matches found: %s",ostr,0); | |
202 | free(matchbuf); | |
203 | return; | |
204 | } else { | |
205 | *matchptr++ = strdup(ostr); | |
206 | matchct = 1; | |
207 | } | |
208 | qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp); | |
209 | matchptr = matchbuf; | |
210 | while (matchct--) /* insert matches in the arg list */ | |
211 | insnode(list,node,*matchptr++); | |
212 | free(matchbuf); | |
213 | *np = (next) ? prevnode(next) : lastnode(list); | |
214 | } | |
215 | ||
216 | /* get number after qualifier */ | |
217 | ||
218 | long qgetnum(s) /**/ | |
219 | char **s; | |
220 | { | |
221 | long v = 0; | |
222 | ||
223 | if (!idigit(**s)) | |
224 | { | |
225 | zerr("number expected",NULL,0); | |
226 | return 0; | |
227 | } | |
228 | while (idigit(**s)) | |
229 | v = v*10+*(*s)++-'0'; | |
230 | return v; | |
231 | } | |
232 | ||
233 | int notstrcmp(a,b) /**/ | |
234 | char **a;char **b; | |
235 | { | |
236 | char *c = *b,*d = *a; | |
237 | int x1,x2; | |
238 | ||
239 | for (; *c == *d && *c; c++,d++); | |
240 | x1 = atoi(c); x2 = atoi(d); | |
241 | if (x1==x2 || unset(NUMERICGLOBSORT)) | |
242 | return ((int) (unsigned char) *c-(int) (unsigned char) *d); | |
243 | return x1-x2; | |
244 | } | |
245 | ||
246 | int forstrcmp(a,b) /**/ | |
247 | char **a;char **b; | |
248 | { | |
249 | char *c = *b,*d = *a; | |
250 | ||
251 | for (; *c == *d && *c; c++,d++); | |
252 | return ((int) (unsigned char) *d-(int) (unsigned char) *c); | |
253 | } | |
254 | ||
255 | /* add a match to the list */ | |
256 | ||
257 | void insert(s) /**/ | |
258 | char *s; | |
259 | { | |
260 | struct stat buf; | |
261 | int statted = 0; | |
262 | ||
263 | if (exclude && domatch(s,exclude,gf_noglobdots)) return; | |
264 | if (gf_markdirs && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) { | |
265 | char *t; | |
266 | int ll = strlen(s); | |
267 | ||
268 | t = ncalloc(ll+2); | |
269 | strcpy(t,s); | |
270 | t[ll] = '/'; | |
271 | t[ll+1] = '\0'; | |
272 | s = t; | |
273 | statted = 1; | |
274 | } | |
275 | if (qualct) { /* do the (X) (^X) stuff */ | |
276 | int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs; | |
277 | int *sptr = qualsense; | |
278 | long *lptr = qualdata; | |
279 | struct stat buf; | |
280 | ||
281 | if (statted || lstat(s,&buf) >= 0) | |
282 | while (*fptr) if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++)) return; | |
283 | } | |
284 | *matchptr++ = s; | |
285 | if (++matchct == matchsz) { | |
286 | matchbuf = (char **) realloc((char *) matchbuf, | |
287 | sizeof(char **)*(matchsz *= 2)); | |
288 | matchptr = matchbuf+matchct; | |
289 | } | |
290 | } | |
291 | ||
292 | /* check to see if str is eligible for filename generation */ | |
293 | ||
294 | int haswilds(str) /**/ | |
295 | char *str; | |
296 | { | |
297 | if ((*str == Inbrack || *str == Outbrack) && !str[1]) return 0; | |
298 | if (str[0] == '%') return 0; | |
299 | for (; *str; str++) | |
300 | if (*str == Pound || *str == Hat || *str == Star || | |
301 | *str == Bar || *str == Inbrack || *str == Inang || | |
302 | *str == Quest) return 1; | |
303 | return 0; | |
304 | } | |
305 | ||
306 | /* check to see if str is eligible for brace expansion */ | |
307 | ||
308 | int hasbraces(str) /**/ | |
309 | char *str; | |
310 | { | |
311 | int mb,bc,cmct1,cmct2; | |
312 | char *lbr = NULL; | |
313 | ||
314 | if (str[0] == Inbrace && str[1] == Outbrace) | |
315 | return 0; | |
316 | if (isset(BRACECCL)) { | |
317 | for (mb = bc = 0; *str; ++str) | |
318 | if (*str == Inbrace) { | |
319 | if (++bc > mb) | |
320 | mb = bc; | |
321 | } | |
322 | else if (*str == Outbrace) | |
323 | if (--bc < 0) | |
324 | return(0); | |
325 | return(mb && bc == 0); | |
326 | } | |
327 | for (mb = bc = cmct1 = cmct2 = 0; *str; str++) | |
328 | { | |
329 | if (*str == Inbrace) | |
330 | { | |
331 | if (!bc) | |
332 | lbr = str; | |
333 | bc++; | |
334 | if (str[4] == Outbrace && str[2] == '-') /* {a-z} */ | |
335 | { | |
336 | cmct1++; | |
337 | if (bc == 1) | |
338 | cmct2++; | |
339 | } | |
340 | } | |
341 | else if (*str == Outbrace) | |
342 | { | |
343 | bc--; | |
344 | if (!bc) | |
345 | { | |
346 | if (!cmct2) | |
347 | { | |
348 | *lbr = '{'; | |
349 | *str = '}'; | |
350 | } | |
351 | cmct2 = 0; | |
352 | } | |
353 | } | |
354 | else if (*str == Comma && bc) | |
355 | { | |
356 | cmct1++; | |
357 | if (bc == 1) | |
358 | cmct2++; | |
359 | } | |
360 | if (bc > mb) | |
361 | mb = bc; | |
362 | if (bc < 0) | |
363 | return 0; | |
364 | } | |
365 | return (mb && bc == 0 && cmct1); | |
366 | } | |
367 | ||
368 | /* expand stuff like >>*.c */ | |
369 | ||
370 | int xpandredir(fn,tab) /**/ | |
371 | struct redir *fn;Lklist tab; | |
372 | { | |
373 | Lklist fake; | |
374 | char *nam; | |
375 | struct redir *ff; | |
376 | int ret = 0; | |
377 | ||
378 | fake = newlist(); | |
379 | addnode(fake,fn->name); | |
380 | prefork(fake); | |
381 | if (!errflag) | |
382 | postfork(fake,1); | |
383 | if (errflag) return 0; | |
384 | if (full(fake) && !nextnode(firstnode(fake))) { | |
385 | fn->name = peekfirst(fake); | |
386 | untokenize(fn->name); | |
387 | } else | |
388 | while (nam = ugetnode(fake)) { | |
389 | ff = alloc(sizeof *ff); | |
390 | *ff = *fn; | |
391 | ff->name = nam; | |
392 | addnode(tab,ff); | |
393 | ret = 1; | |
394 | } | |
395 | return ret; | |
396 | } | |
397 | ||
398 | /* concatenate s1 and s2 in dynamically allocated buffer */ | |
399 | ||
400 | char *dyncat(s1,s2) /**/ | |
401 | char *s1;char *s2; | |
402 | { | |
403 | char *ptr; | |
404 | ||
405 | ptr = ncalloc(strlen(s1)+strlen(s2)+1); | |
406 | strcpy(ptr,s1); | |
407 | strcat(ptr,s2); | |
408 | return ptr; | |
409 | } | |
410 | ||
411 | /* concatenate s1, s2, and s3 in dynamically allocated buffer */ | |
412 | ||
413 | char *tricat(s1,s2,s3) /**/ | |
414 | char *s1;char *s2;char *s3; | |
415 | { | |
416 | char *ptr; | |
417 | ||
418 | ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1); | |
419 | strcpy(ptr,s1); | |
420 | strcat(ptr,s2); | |
421 | strcat(ptr,s3); | |
422 | return ptr; | |
423 | } | |
424 | ||
425 | /* brace expansion */ | |
426 | ||
427 | void xpandbraces(list,np) /**/ | |
428 | Lklist list;Lknode *np; | |
429 | { | |
430 | Lknode node = (*np),last = prevnode(node); | |
431 | char *str = getdata(node),*str3 = str,*str2; | |
432 | int prev, bc, comma; | |
433 | ||
434 | for (; *str != Inbrace; str++); | |
435 | for (str2 = str, bc = comma = 0; *str2; ++str2) | |
436 | if (*str2 == Inbrace) | |
437 | ++bc; | |
438 | else if (*str2 == Outbrace) { | |
439 | if (--bc == 0) | |
440 | break; | |
441 | } | |
442 | else if (bc == 1 && *str2 == Comma) | |
443 | ++comma; | |
444 | if (!comma && !bc && isset(BRACECCL)) { /* {a-mnop} */ | |
445 | char ccl[256], *p; | |
446 | unsigned char c1,c2,lastch; | |
447 | ||
448 | uremnode(list,node); | |
449 | memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0])); | |
450 | for (p = str + 1, lastch = 0; p < str2; ) { | |
451 | if (itok(c1 = *p++)) | |
452 | c1 = ztokens[c1 - (unsigned char)Pound]; | |
453 | if (itok(c2 = *p)) | |
454 | c2 = ztokens[c2 - (unsigned char)Pound]; | |
455 | if (c1 == '-' && lastch && p < str2 && lastch <= c2) { | |
456 | while (lastch < c2) | |
457 | ccl[lastch++] = 1; | |
458 | lastch = 0; | |
459 | } | |
460 | else | |
461 | ccl[lastch = c1] = 1; | |
462 | } | |
463 | strcpy(str + 1, str2 + 1); | |
464 | for (p = ccl+255; p-- > ccl; ) | |
465 | if (*p) { | |
466 | *str = p - ccl; | |
467 | insnode(list, last, strdup(str3)); | |
468 | } | |
469 | *np = nextnode(last); | |
470 | return; | |
471 | } | |
472 | if (str[2] == '-' && str[4] == Outbrace) /* {a-z} */ | |
473 | { | |
474 | char c1,c2; | |
475 | ||
476 | uremnode(list,node); | |
477 | chuck(str); | |
478 | c1 = *str; | |
479 | chuck(str); | |
480 | chuck(str); | |
481 | c2 = *str; | |
482 | chuck(str); | |
483 | if (itok(c1)) | |
484 | c1 = ztokens[c1-Pound]; | |
485 | if (itok(c2)) | |
486 | c2 = ztokens[c2-Pound]; | |
487 | if (c1 < c2) | |
488 | for (; c2 >= c1; c2--) /* {a-z} */ | |
489 | { | |
490 | *str = c2; | |
491 | insnode(list,last,strdup(str3)); | |
492 | } | |
493 | else | |
494 | for (; c2 <= c1; c2++) /* {z-a} */ | |
495 | { | |
496 | *str = c2; | |
497 | insnode(list,last,strdup(str3)); | |
498 | } | |
499 | *np = nextnode(last); | |
500 | return; | |
501 | } | |
502 | prev = str-str3; | |
503 | str2 = getparen(str++); | |
504 | if (!str2) | |
505 | { | |
506 | zerr("how did you get this error?",NULL,0); | |
507 | return; | |
508 | } | |
509 | uremnode(list,node); | |
510 | node = last; | |
511 | for(;;) | |
512 | { | |
513 | char *zz,*str4; | |
514 | int cnt; | |
515 | ||
516 | for (str4 = str, cnt = 0; cnt || *str != Comma && *str != | |
517 | Outbrace; str++) | |
518 | if (*str == Inbrace) | |
519 | cnt++; | |
520 | else if (*str == Outbrace) | |
521 | cnt--; | |
522 | else if (!*str) | |
523 | exit(10); | |
524 | zz = zalloc(prev+(str-str4)+strlen(str2)+1); | |
525 | ztrncpy(zz,str3,prev); | |
526 | strncat(zz,str4,str-str4); | |
527 | strcat(zz,str2); | |
528 | insnode(list,node,zz); | |
529 | incnode(node); | |
530 | if (*str != Outbrace) | |
531 | str++; | |
532 | else | |
533 | break; | |
534 | } | |
535 | *np = nextnode(last); | |
536 | } | |
537 | ||
538 | /* get closing paren, given pointer to opening paren */ | |
539 | ||
540 | char *getparen(str) /**/ | |
541 | char *str; | |
542 | { | |
543 | int cnt = 1; | |
544 | char typein = *str++,typeout = typein+1; | |
545 | ||
546 | for (; *str && cnt; str++) | |
547 | if (*str == typein) | |
548 | cnt++; | |
549 | else if (*str == typeout) | |
550 | cnt--; | |
551 | if (!str && cnt) | |
552 | return NULL; | |
553 | return str; | |
554 | } | |
555 | ||
556 | /* check to see if a matches b (b is not a filename pattern) */ | |
557 | ||
558 | int matchpat(a,b) /**/ | |
559 | char *a;char *b; | |
560 | { | |
561 | Comp c; | |
562 | int val,len; | |
563 | char *b2; | |
564 | ||
565 | remnulargs(b); | |
566 | len = strlen(b); | |
567 | b2 = alloc(len+3); | |
568 | strcpy(b2+1,b); | |
569 | b2[0] = Inpar; | |
570 | b2[len+1] = Outpar; | |
571 | b2[len+2] = '\0'; | |
572 | c = parsereg(b2); | |
573 | if (!c) | |
574 | { | |
575 | zerr("bad pattern: %s",b,0); | |
576 | return 0; | |
577 | } | |
578 | val = domatch(a,c,0); | |
579 | return val; | |
580 | } | |
581 | ||
582 | /* do the ${foo%%bar}, ${foo#bar} stuff */ | |
583 | /* please do not laugh at this code. */ | |
584 | ||
585 | void getmatch(sp,pat,dd) /**/ | |
586 | char **sp;char *pat;int dd; | |
587 | { | |
588 | Comp c; | |
589 | char *t,*lng = NULL,cc,*s = *sp; | |
590 | ||
591 | remnulargs(pat); | |
592 | c = parsereg(pat); | |
593 | if (!c) | |
594 | { | |
595 | zerr("bad pattern: %s",pat,0); | |
596 | return; | |
597 | } | |
598 | if (!(dd & 2)) | |
599 | { | |
600 | for (t = s; t==s || t[-1]; t++) | |
601 | { | |
602 | cc = *t; | |
603 | *t = '\0'; | |
604 | if (domatch(s,c,0)) | |
605 | { | |
606 | if (!(dd & 1)) | |
607 | { | |
608 | *t = cc; | |
609 | t = strdup(t); | |
610 | *sp = t; | |
611 | return; | |
612 | } | |
613 | lng = t; | |
614 | } | |
615 | *t = cc; | |
616 | } | |
617 | if (lng) | |
618 | { | |
619 | t = strdup(lng); | |
620 | *sp = t; | |
621 | return; | |
622 | } | |
623 | } | |
624 | else | |
625 | { | |
626 | for (t = s+strlen(s); t >= s; t--) | |
627 | { | |
628 | if (domatch(t,c,0)) | |
629 | { | |
630 | if (!(dd & 1)) | |
631 | { | |
632 | cc = *t; | |
633 | *t = '\0'; | |
634 | *sp = strdup(*sp); | |
635 | *t = cc; | |
636 | return; | |
637 | } | |
638 | lng = t; | |
639 | } | |
640 | } | |
641 | if (lng) | |
642 | { | |
643 | cc = *lng; | |
644 | *lng = '\0'; | |
645 | *sp = strdup(*sp); | |
646 | *lng = cc; | |
647 | return; | |
648 | } | |
649 | } | |
650 | } | |
651 | ||
652 | /* add a component to pathbuf */ | |
653 | ||
654 | static int addpath(s) | |
655 | char *s; | |
656 | { | |
657 | if (strlen(s)+pathpos >= MAXPATHLEN) return 0; | |
658 | while (pathbuf[pathpos++] = *s++); | |
659 | pathbuf[pathpos-1] = '/'; | |
660 | pathbuf[pathpos] = '\0'; | |
661 | return 1; | |
662 | } | |
663 | ||
664 | char *getfullpath(s) /**/ | |
665 | char *s; | |
666 | { | |
667 | static char buf[MAXPATHLEN]; | |
668 | ||
669 | strcpy(buf,pathbuf); | |
670 | strcat(buf,s); | |
671 | return buf; | |
672 | } | |
673 | ||
674 | /* do the globbing */ | |
675 | ||
676 | void scanner(q) /**/ | |
677 | Complist q; | |
678 | { | |
679 | Comp c; | |
680 | int closure; | |
681 | ||
682 | if (closure = q->closure) /* (foo/)# */ | |
683 | if (q->closure == 2) /* (foo/)## */ | |
684 | q->closure = 1; | |
685 | else | |
686 | scanner(q->next); | |
687 | if (c = q->comp) | |
688 | { | |
689 | if (!(c->next || c->left) && !haswilds(c->str)) | |
690 | if (q->next) | |
691 | { | |
692 | int oppos = pathpos; | |
693 | ||
694 | if (errflag) | |
695 | return; | |
696 | if (q->closure && !strcmp(c->str,".")) return; | |
697 | if (!addpath(c->str)) return; | |
698 | if (!closure || exists(pathbuf)) | |
699 | scanner((q->closure) ? q : q->next); | |
700 | pathbuf[pathpos = oppos] = '\0'; | |
701 | } | |
702 | else | |
703 | { | |
704 | char *s; | |
705 | ||
706 | if (exists(s = getfullpath(c->str))) | |
707 | insert(strdup(s)); | |
708 | } | |
709 | else | |
710 | { | |
711 | char *fn; | |
712 | int dirs = !!q->next; | |
713 | struct direct *de; | |
714 | DIR *lock = opendir((*pathbuf) ? pathbuf : "."); | |
715 | ||
716 | if (lock == NULL) | |
717 | return; | |
718 | readdir(lock); readdir(lock); /* skip . and .. */ | |
719 | while (de = readdir(lock)) | |
720 | { | |
721 | if (errflag) | |
722 | break; | |
723 | fn = &de->d_name[0]; | |
724 | if (domatch(fn,c,gf_noglobdots)) | |
725 | { | |
726 | int oppos = pathpos; | |
727 | ||
728 | if (dirs) | |
729 | { | |
730 | if (closure) | |
731 | { | |
732 | int type3; | |
733 | struct stat buf; | |
734 | ||
735 | if (lstat(getfullpath(fn),&buf) == -1) | |
736 | { | |
737 | if (errno != ENOENT && errno != EINTR && | |
738 | errno != ENOTDIR) | |
739 | { | |
740 | zerr("%e: %s",fn,errno); | |
741 | errflag = 0; | |
742 | } | |
743 | continue; | |
744 | } | |
745 | type3 = buf.st_mode & S_IFMT; | |
746 | if (type3 != S_IFDIR) | |
747 | continue; | |
748 | } | |
749 | if (addpath(fn)) | |
750 | scanner((q->closure) ? q : q->next); /* scan next level */ | |
751 | pathbuf[pathpos = oppos] = '\0'; | |
752 | } | |
753 | else insert(dyncat(pathbuf,fn)); | |
754 | } | |
755 | } | |
756 | closedir(lock); | |
757 | } | |
758 | } | |
759 | else | |
760 | zerr("no idea how you got this error message.",NULL,0); | |
761 | } | |
762 | ||
763 | /* do the [..(foo)..] business */ | |
764 | ||
765 | int minimatch(pat,str) /**/ | |
766 | char **pat;char **str; | |
767 | { | |
768 | char *pt = *pat+1,*s = *str; | |
769 | ||
770 | for (; *pt != Outpar; s++,pt++) | |
771 | if ((*pt != Quest || !*s) && *pt != *s) | |
772 | { | |
773 | *pat = getparen(*pat)-1; | |
774 | return 0; | |
775 | } | |
776 | *str = s-1; | |
777 | return 1; | |
778 | } | |
779 | ||
780 | static char *pptr; | |
781 | static Comp tail = 0; | |
782 | static int first; | |
783 | ||
784 | int domatch(str,c,fist) /**/ | |
785 | char *str;Comp c;int fist; | |
786 | { | |
787 | pptr = str; | |
788 | first = fist; | |
789 | return doesmatch(c); | |
790 | } | |
791 | ||
792 | /* see if current pattern matches c */ | |
793 | ||
794 | int doesmatch(c) /**/ | |
795 | Comp c; | |
796 | { | |
797 | char *pat = c->str; | |
798 | ||
799 | if (c->closure == 1) { | |
800 | char *saves = pptr; | |
801 | ||
802 | if (first && *pptr == '.') return 0; | |
803 | if (doesmatch(c->next)) return 1; | |
804 | pptr = saves; | |
805 | first = 0; | |
806 | } | |
807 | for(;;) | |
808 | { | |
809 | if (!pat || !*pat) | |
810 | { | |
811 | char *saves; | |
812 | int savei; | |
813 | ||
814 | if (errflag) | |
815 | return 0; | |
816 | saves = pptr; | |
817 | savei = first; | |
818 | if (c->left || c->right) | |
819 | if (!doesmatch(c->left)) | |
820 | if (c->right) | |
821 | { | |
822 | pptr = saves; | |
823 | first = savei; | |
824 | if (!doesmatch(c->right)) | |
825 | return 0; | |
826 | } | |
827 | else | |
828 | return 0; | |
829 | if (c->closure) | |
830 | return doesmatch(c); | |
831 | if (!c->next) | |
832 | return (!c->last || !*pptr); | |
833 | return doesmatch(c->next); | |
834 | } | |
835 | if (first && *pptr == '.' && *pat != '.') | |
836 | return 0; | |
837 | if (*pat == Star) /* final * is not expanded to ?#; returns success */ | |
838 | { | |
839 | while (*pptr) pptr++; | |
840 | return 1; | |
841 | } | |
842 | first = 0; | |
843 | if (*pat == Quest && *pptr) | |
844 | { | |
845 | pptr++; | |
846 | pat++; | |
847 | continue; | |
848 | } | |
849 | if (*pat == Hat) | |
850 | return 1-doesmatch(c->next); | |
851 | if (*pat == Inbrack) { | |
852 | if (!*pptr) break; | |
853 | if (pat[1] == Hat || pat[1] == '^') { | |
854 | pat[1] = Hat; | |
855 | for (pat += 2; *pat != Outbrack && *pat; pat++) | |
856 | if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) { | |
857 | if (pat[-1] <= *pptr && pat[1] >= *pptr) | |
858 | break; | |
859 | } else if (*pptr == *pat) break; | |
860 | if (!*pat) { | |
861 | zerr("something is very wrong.",NULL,0); | |
862 | return 0; | |
863 | } | |
864 | if (*pat != Outbrack) | |
865 | break; | |
866 | pat++; | |
867 | pptr++; | |
868 | continue; | |
869 | } else { | |
870 | for (pat++; *pat != Outbrack && *pat; pat++) | |
871 | if (*pat == Inpar) { | |
872 | if (minimatch(&pat,&pptr)) | |
873 | break; | |
874 | } else if (*pat == '-' && pat[-1] != Inbrack && | |
875 | pat[1] != Outbrack) { | |
876 | if (pat[-1] <= *pptr && pat[1] >= *pptr) | |
877 | break; | |
878 | } else if (*pptr == *pat) break; | |
879 | if (!pat || !*pat) { | |
880 | zerr("oh dear. that CAN'T be right.",NULL,0); | |
881 | return 0; | |
882 | } | |
883 | if (*pat == Outbrack) | |
884 | break; | |
885 | for (pptr++; *pat != Outbrack; pat++); | |
886 | pat++; | |
887 | continue; | |
888 | } | |
889 | } | |
890 | if (*pat == Inang) | |
891 | { | |
892 | int t1,t2,t3; | |
893 | char *ptr; | |
894 | ||
895 | if (*++pat == Outang) /* handle <> case */ | |
896 | { | |
897 | ( void ) zstrtol(pptr,&ptr,10); | |
898 | if (ptr == pptr) | |
899 | break; | |
900 | pptr = ptr; | |
901 | pat++; | |
902 | } | |
903 | else | |
904 | { | |
905 | t1 = zstrtol(pptr,&ptr,10); | |
906 | if (ptr == pptr) | |
907 | break; | |
908 | pptr = ptr; | |
909 | t2 = zstrtol(pat,&ptr,10); | |
910 | if (*ptr != '-') | |
911 | exit(31); | |
912 | t3 = zstrtol(ptr+1,&pat,10); | |
913 | if (!t3) | |
914 | t3 = -1; | |
915 | if (*pat++ != Outang) | |
916 | exit(21); | |
917 | if (t1 < t2 || (t3 != -1 && t1 > t3)) | |
918 | break; | |
919 | } | |
920 | continue; | |
921 | } | |
922 | if (*pptr == *pat) | |
923 | { | |
924 | pptr++; | |
925 | pat++; | |
926 | continue; | |
927 | } | |
928 | break; | |
929 | } | |
930 | return 0; | |
931 | } | |
932 | ||
933 | Complist parsepat(str) /**/ | |
934 | char *str; | |
935 | { | |
936 | char *s; | |
937 | ||
938 | exclude = NULL; | |
939 | if (isset(EXTENDEDGLOB)) { | |
940 | s = str+strlen(str); | |
941 | while (s-- > str) { | |
942 | if (*s == Tilde && s[1]) { | |
943 | *s++ = '\0'; | |
944 | exclude = parsereg(s); | |
945 | if (!exclude) return NULL; | |
946 | break; | |
947 | } | |
948 | } | |
949 | } | |
950 | mode = 0; | |
951 | pptr = str; | |
952 | return parsecomplist(); | |
953 | } | |
954 | ||
955 | Comp parsereg(str) /**/ | |
956 | char *str; | |
957 | { | |
958 | mode = 1; | |
959 | pptr = str; | |
960 | return parsecompsw(); | |
961 | } | |
962 | ||
963 | Complist parsecomplist() /**/ | |
964 | { | |
965 | Comp c1; | |
966 | Complist p1; | |
967 | ||
968 | if (pptr[0] == Star && pptr[1] == Star && | |
969 | (pptr[2] == '/' || | |
970 | (pptr[2] == Star && pptr[3] == Star && pptr[4] == '/'))) { | |
971 | pptr += 3; | |
972 | if (pptr[-1] == Star) pptr += 2; | |
973 | p1 = (Complist) alloc(sizeof *p1); | |
974 | p1->next = parsecomplist(); | |
975 | p1->comp = (Comp) alloc(sizeof *p1->comp); | |
976 | p1->comp->last = 1; | |
977 | p1->comp->str = strdup("*"); | |
978 | *p1->comp->str = Star; | |
979 | p1->closure = 1; | |
980 | return p1; | |
981 | } | |
982 | if (*pptr == Inpar) | |
983 | { | |
984 | char *str; | |
985 | int pars = 1; | |
986 | ||
987 | for (str = pptr+1; *str && pars; str++) | |
988 | if (*str == Inpar) | |
989 | pars++; | |
990 | else if (*str == Outpar) | |
991 | pars--; | |
992 | if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/') | |
993 | goto kludge; | |
994 | pptr++; | |
995 | if (!(c1 = parsecompsw())) | |
996 | return NULL; | |
997 | if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound) | |
998 | { | |
999 | int pdflag = 0; | |
1000 | ||
1001 | pptr += 3; | |
1002 | if (*pptr == Pound) | |
1003 | { | |
1004 | pdflag = 1; | |
1005 | pptr++; | |
1006 | } | |
1007 | p1 = (Complist) alloc(sizeof *p1); | |
1008 | p1->comp = c1; | |
1009 | p1->closure = 1+pdflag; | |
1010 | p1->next = parsecomplist(); | |
1011 | return (p1->comp) ? p1 : NULL; | |
1012 | } | |
1013 | } | |
1014 | else | |
1015 | { | |
1016 | kludge: | |
1017 | if (!(c1 = parsecompsw())) | |
1018 | return NULL; | |
1019 | if (*pptr == '/' || !*pptr) | |
1020 | { | |
1021 | int ef = *pptr == '/'; | |
1022 | ||
1023 | p1 = (Complist) alloc(sizeof *p1); | |
1024 | p1->comp = c1; | |
1025 | p1->closure = 0; | |
1026 | p1->next = (*pptr == '/') ? (pptr++,parsecomplist()) : NULL; | |
1027 | return (ef && !p1->next) ? NULL : p1; | |
1028 | } | |
1029 | } | |
1030 | errflag = 1; | |
1031 | return NULL; | |
1032 | } | |
1033 | ||
1034 | Comp parsecomp() /**/ | |
1035 | { | |
1036 | Comp c = (Comp) alloc(sizeof *c),c1,c2; | |
1037 | char *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL; | |
1038 | ||
1039 | c->next = tail; | |
1040 | ||
1041 | while (*pptr && (mode || *pptr != '/') && *pptr != Bar && | |
1042 | *pptr != Outpar) | |
1043 | { | |
1044 | if (*pptr == Hat) | |
1045 | { | |
1046 | *s++ = Hat; | |
1047 | *s++ = '\0'; | |
1048 | pptr++; | |
1049 | if (!(c->next = parsecomp())) | |
1050 | return NULL; | |
1051 | return c; | |
1052 | } | |
1053 | if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/')) | |
1054 | { | |
1055 | *s++ = '\0'; | |
1056 | pptr++; | |
1057 | c1 = (Comp) alloc(sizeof *c1); | |
1058 | *(c1->str = strdup("?")) = Quest; | |
1059 | c1->closure = 1; | |
1060 | if (!(c2 = parsecomp())) return NULL; | |
1061 | c1->next = c2; | |
1062 | c->next = c1; | |
1063 | return c; | |
1064 | } | |
1065 | if (*pptr == Inpar) | |
1066 | { | |
1067 | int pars = 1; | |
1068 | char *startp = pptr, *endp; | |
1069 | Comp stail = tail; | |
1070 | int dpnd = 0; | |
1071 | ||
1072 | for (pptr = pptr+1; *pptr && pars; pptr++) | |
1073 | if (*pptr == Inpar) | |
1074 | pars++; | |
1075 | else if (*pptr == Outpar) | |
1076 | pars--; | |
1077 | if (pptr[-1] != Outpar) | |
1078 | { | |
1079 | errflag = 1; | |
1080 | return NULL; | |
1081 | } | |
1082 | if (*pptr == Pound) | |
1083 | { | |
1084 | dpnd = 1; | |
1085 | pptr++; | |
1086 | if (*pptr == Pound) | |
1087 | { | |
1088 | pptr++; | |
1089 | dpnd = 2; | |
1090 | } | |
1091 | } | |
1092 | if (!(c1 = parsecomp())) return NULL; | |
1093 | tail = c1; | |
1094 | endp = pptr; | |
1095 | pptr = startp; | |
1096 | pptr++; | |
1097 | *s++ = '\0'; | |
1098 | c->next = (Comp) alloc(sizeof *c); | |
1099 | c->next->left = parsecompsw(); | |
1100 | c->next->closure = dpnd; | |
1101 | c->next->next = (Comp) alloc(sizeof *c); | |
1102 | pptr = endp; | |
1103 | tail = stail; | |
1104 | return c; | |
1105 | } | |
1106 | if (*pptr == Pound) | |
1107 | { | |
1108 | *s = '\0'; | |
1109 | pptr++; | |
1110 | if (!ls) | |
1111 | return NULL; | |
1112 | if (*pptr == Pound) | |
1113 | { | |
1114 | pptr++; | |
1115 | c->next = c1 = (Comp) alloc(sizeof *c); | |
1116 | c1->str = strdup(ls); | |
1117 | } | |
1118 | else | |
1119 | c1 = c; | |
1120 | c1->next = c2 = (Comp) alloc(sizeof *c); | |
1121 | c2->str = strdup(ls); | |
1122 | c2->closure = 1; | |
1123 | c2->next = parsecomp(); | |
1124 | if (!c2->next) | |
1125 | return NULL; | |
1126 | *ls++ = '\0'; | |
1127 | return c; | |
1128 | } | |
1129 | ls = s; | |
1130 | if (*pptr == Inang) | |
1131 | { | |
1132 | int dshct; | |
1133 | ||
1134 | dshct = (pptr[1] == Outang); | |
1135 | *s++ = *pptr++; | |
1136 | while (*pptr && (*s++ = *pptr++) != Outang) | |
1137 | if (s[-1] == '-') | |
1138 | dshct++; | |
1139 | else if (!idigit(s[-1])) | |
1140 | break; | |
1141 | if (s[-1] != Outang || dshct != 1) | |
1142 | return NULL; | |
1143 | } | |
1144 | else if (*pptr == Inbrack) | |
1145 | { | |
1146 | while (*pptr && (*s++ = *pptr++) != Outbrack); | |
1147 | if (s[-1] != Outbrack) | |
1148 | return NULL; | |
1149 | } | |
1150 | else if (itok(*pptr) && *pptr != Star && *pptr != Quest) | |
1151 | *s++ = ztokens[*pptr++-Pound]; | |
1152 | else | |
1153 | *s++ = *pptr++; | |
1154 | } | |
1155 | if (*pptr == '/' || !*pptr) | |
1156 | c->last = 1; | |
1157 | *s++ = '\0'; | |
1158 | return c; | |
1159 | } | |
1160 | ||
1161 | Comp parsecompsw() /**/ | |
1162 | { | |
1163 | Comp c1,c2,c3; | |
1164 | ||
1165 | c1 = parsecomp(); | |
1166 | if (!c1) | |
1167 | return NULL; | |
1168 | if (*pptr == Bar) | |
1169 | { | |
1170 | c2 = (Comp) alloc(sizeof *c2); | |
1171 | pptr++; | |
1172 | c3 = parsecompsw(); | |
1173 | if (!c3) | |
1174 | return NULL; | |
1175 | c2->str = strdup(""); | |
1176 | c2->left = c1; | |
1177 | c2->right = c3; | |
1178 | return c2; | |
1179 | } | |
1180 | return c1; | |
1181 | } | |
1182 | ||
1183 | /* tokenize and see if ss matches tt */ | |
1184 | ||
1185 | int patmatch(ss,tt) /**/ | |
1186 | char *ss;char *tt; | |
1187 | { | |
1188 | char *s = ss,*t; | |
1189 | ||
1190 | for (; *s; s++) | |
1191 | if (*s == '\\') | |
1192 | chuck(s); | |
1193 | else | |
1194 | for (t = ztokens; *t; t++) | |
1195 | if (*t == *s) | |
1196 | { | |
1197 | *s = (t-ztokens)+Pound; | |
1198 | break; | |
1199 | } | |
1200 | return matchpat(ss,tt); | |
1201 | } | |
1202 | ||
1203 | /* remove unnecessary Nulargs */ | |
1204 | ||
1205 | void remnulargs(s) /**/ | |
1206 | char *s; | |
1207 | { | |
1208 | int nl = *s; | |
1209 | char *t = s; | |
1210 | ||
1211 | while (*s) | |
1212 | if (*s == Nularg) | |
1213 | chuck(s); | |
1214 | else | |
1215 | s++; | |
1216 | if (!*t && nl) | |
1217 | { | |
1218 | t[0] = Nularg; | |
1219 | t[1] = '\0'; | |
1220 | } | |
1221 | } | |
1222 | ||
1223 | /* qualifier functions */ | |
1224 | ||
1225 | int qualdev(buf,dv) /**/ | |
1226 | struct stat *buf;long dv; | |
1227 | { | |
1228 | return buf->st_dev == dv; | |
1229 | } | |
1230 | ||
1231 | int qualnlink(buf,ct) /**/ | |
1232 | struct stat *buf;long ct; | |
1233 | { | |
1234 | return buf->st_nlink == ct; | |
1235 | } | |
1236 | ||
1237 | int qualuid(buf,uid) /**/ | |
1238 | struct stat *buf;long uid; | |
1239 | { | |
1240 | return buf->st_uid == uid; | |
1241 | } | |
1242 | ||
1243 | int qualgid(buf,gid) /**/ | |
1244 | struct stat *buf;long gid; | |
1245 | { | |
1246 | return buf->st_gid == gid; | |
1247 | } | |
1248 | ||
1249 | int qualisdev(buf,junk) /**/ | |
1250 | struct stat *buf;long junk; | |
1251 | { | |
1252 | junk = buf->st_mode & S_IFMT; | |
1253 | return junk == S_IFBLK || junk == S_IFCHR; | |
1254 | } | |
1255 | ||
1256 | int qualmode(buf,mod) /**/ | |
1257 | struct stat *buf;long mod; | |
1258 | { | |
1259 | return (buf->st_mode & S_IFMT) == mod; | |
1260 | } | |
1261 | ||
1262 | int qualflags(buf,mod) /**/ | |
1263 | struct stat *buf;long mod; | |
1264 | { | |
1265 | return buf->st_mode & mod; | |
1266 | } | |
1267 | ||
1268 | int qualiscom(buf,mod) /**/ | |
1269 | struct stat *buf;long mod; | |
1270 | { | |
1271 | return (buf->st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC); | |
1272 | } | |
1273 |