/[mit-cadr]/branches/ggilley/emulator/usim/glob.c
ViewVC logotype

Contents of /branches/ggilley/emulator/usim/glob.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 410 - (show annotations)
Sun Mar 3 22:44:10 2013 UTC (13 months, 2 weeks ago) by ggilley
File MIME type: text/plain
File size: 17382 byte(s)
fix an error and some warnings
1 /*
2 */
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/param.h>
8 #include <sys/stat.h>
9 #include <sys/dir.h>
10 #include <errno.h>
11 #include <pwd.h>
12
13 #include "Files.h"
14 #include "glob.h"
15
16 #if defined(linux) || defined(OSX)
17 #include <dirent.h>
18 #include <stdlib.h>
19 #endif
20
21 #define QUOTE 0200
22 #define TRIM 0177
23 #define eq(a,b) (strcmp(a, b)==0)
24 #define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
25
26 static char **gargv; /* Pointer to the (stack) arglist */
27 static int gargc; /* Number args in gargv */
28 static int gargmax;
29 static short gflag;
30 static int tglob(register char c);
31 char **glob();
32 int globerr;
33 char *home;
34 struct passwd *getpwnam();
35 extern int errno;
36 static char *strend();
37 /*char *malloc(), *strcpy(), *strcat(), *sprintf();*/
38
39 static void ginit();
40 static void collect(register char *as);
41 static void acollect();
42 static void sort();
43 static void expand();
44 static void matchdir();
45 static int execbrc();
46 static int match();
47 static int amatch();
48 static void Gcat(char *s1, char *s2);
49 static void addpath(char);
50 static void rscan(char **t, int (*f)(char));
51 static char *strspl(char *cp, char *dp);
52
53 int letter(register char c);
54 int digit(register char c);
55 int any(register int c, register char *s);
56
57 int gethdir(char *home);
58
59 int blklen(register char **av);
60 char **blkcpy(char **oav, register char **bv);
61 char **copyblk(register char **v);
62 void blkfree(char **av0);
63 void fatal(char *fmt, ...);
64
65 static int globcnt;
66
67 char *globchars = "`{[*?";
68
69 static char *gpath, *gpathp, *lastgpathp;
70 static int globbed;
71 static char *entp;
72 static char **sortbas;
73
74 #define STARTVEC 100
75 #define INCVEC 100
76
77 char **
78 glob(register char *v)
79 {
80 char agpath[BUFSIZ];
81 char *vv[2];
82
83 vv[0] = v;
84 vv[1] = 0;
85 gflag = 0;
86 rscan(vv, tglob);
87 if (gflag == 0)
88 {
89 #if 0 // if you do a change properties on a directory, it wants the directory
90 struct stat sbuf;
91
92 // if it's a directory, we're probably looking for the list of contents
93 if (stat(v, &sbuf) == 0) {
94 if ((sbuf.st_mode & S_IFMT) == S_IFDIR)
95 {
96 ssize_t len = strlen(v);
97
98 wild = malloc(len + 3);
99 strcpy(wild, v);
100 if (wild[len] != '/')
101 wild[len++] = '/';
102 wild[len++] = '*';
103 wild[len] = '\0';
104
105 vv[0] = wild;
106 vv[1] = 0;
107 rscan(vv, tglob);
108 if (gflag == 0)
109 {
110 free(wild);
111 vv[0] = v;
112 return copyblk(vv);
113 }
114 }
115 }
116 else
117 #endif
118 return copyblk(vv);
119 }
120
121 globerr = 0;
122 gpath = agpath; gpathp = gpath; *gpathp = 0;
123 lastgpathp = &gpath[sizeof agpath - 2];
124 ginit(); globcnt = 0;
125 collect(vv[0]);
126 if (globcnt == 0 && (gflag&1)) {
127 blkfree(gargv), gargv = 0;
128 lastgpathp = 0;
129 gpathp = 0;
130 gpath = 0;
131 return (0);
132 }
133 lastgpathp = 0;
134 gpathp = 0;
135 gpath = 0;
136 return gargv;
137 }
138
139 void gfree(char **glob)
140 {
141 blkfree(glob);
142 }
143
144 static void
145 ginit()
146 {
147 char **agargv;
148
149 agargv = (char **)malloc((STARTVEC + 1) * sizeof(char *));
150 if (agargv) {
151 gargmax = STARTVEC;
152 agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
153 }
154 else
155 fatal(NOMEM);
156 }
157
158 static void
159 collect(register char *as)
160 {
161 if (eq(as, "{") || eq(as, "{}")) {
162 Gcat(as, "");
163 sort();
164 } else
165 acollect(as);
166 }
167
168 static void
169 acollect(register char *as)
170 {
171 register int ogargc = gargc;
172
173 gpathp = gpath; *gpathp = 0; globbed = 0;
174 expand(as);
175 if (gargc != ogargc)
176 sort();
177 }
178
179 static void
180 sort()
181 {
182 register char **p1, **p2, *c;
183 char **Gvp = &gargv[gargc];
184
185 p1 = sortbas;
186 while (p1 < Gvp-1) {
187 p2 = p1;
188 while (++p2 < Gvp)
189 if (strcmp(*p1, *p2) > 0)
190 c = *p1, *p1 = *p2, *p2 = c;
191 p1++;
192 }
193 sortbas = Gvp;
194 }
195
196 static void
197 expand(char *as)
198 {
199 register char *cs;
200 register char *sgpathp, *oldcs;
201 struct stat stb;
202
203 sgpathp = gpathp;
204 cs = as;
205 if (*cs == '~' && gpathp == gpath) {
206 addpath('~');
207 for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
208 addpath(*cs++);
209 if (!*cs || *cs == '/') {
210 if (gpathp != gpath + 1) {
211 *gpathp = 0;
212 if (gethdir(gpath + 1)) {
213 (void)sprintf(errstring = errbuf,
214 "Unknown user name: %s after '~'",
215 gpath+1);
216 globerr = IPS;
217 }
218 strcpy(gpath, gpath + 1);
219 } else
220 strcpy(gpath, home);
221 gpathp = strend(gpath);
222 }
223 }
224 while (!any(*cs, globchars) && globerr == 0) {
225 if (*cs == 0) {
226 if (!globbed)
227 Gcat(gpath, "");
228 else if (stat(gpath, &stb) >= 0) {
229 Gcat(gpath, "");
230 globcnt++;
231 }
232 goto endit;
233 }
234 addpath(*cs++);
235 }
236 oldcs = cs;
237 while (cs > as && *cs != '/')
238 cs--, gpathp--;
239 if (*cs == '/')
240 cs++, gpathp++;
241 *gpathp = 0;
242 if (*oldcs == '{') {
243 (void)execbrc(cs, ((char *)0));
244 return;
245 }
246 matchdir(cs);
247 endit:
248 gpathp = sgpathp;
249 *gpathp = 0;
250 }
251
252 static void
253 matchdir(char *pattern)
254 {
255 struct stat stb;
256 register int dirf;
257 register struct direct *dp;
258 #if defined(BSD42) || defined(linux) || defined(OSX)
259 DIR *dirp;
260
261 dirp = opendir(gpath);
262 if (dirp != NULL)
263 #if defined(linux) || defined(OSX) || defined(BSD42)
264 dirf = dirfd(dirp);
265 #else
266 dirf = ((struct DIR *)dirp)->dd_fd;
267 #endif
268 else {
269 #else
270
271 struct direct dirbuf[BUFSIZ / sizeof (struct direct)];
272 int cnt;
273
274 if ((dirf = open(gpath, 0)) < 0) {
275 #endif
276 switch(errno) {
277 case ENOENT:
278 globerr = DNF;
279 break;
280 case EACCES:
281 globerr = ATD;
282 errstring = READDIR;
283 break;
284 case ENOTDIR:
285 globerr = DNF;
286 errstring = PATHNOTDIR;
287 break;
288 default:
289 globerr = MSC;
290 errstring = (char *)strerror(errno);
291 }
292 return;
293 }
294 if (fstat(dirf, &stb) < 0)
295 fatal(FSTAT);
296 if (!isdir(stb)) {
297 globerr = DNF;
298 errstring = PATHNOTDIR;
299 return;
300 }
301 #if defined(BSD42) || defined(linux) || defined(OSX)
302 while ((dp = readdir(dirp)) != NULL)
303 #else
304 while ((cnt = read(dirf, (char *)dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0])
305 for (dp = dirbuf, cnt /= sizeof (struct direct); cnt > 0; cnt--, dp++)
306 #endif
307 if (dp->d_ino == 0 ||
308 (dp->d_name[0] == '.' &&
309 (dp->d_name[1] == '\0' ||
310 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))))
311 continue;
312 else {
313 #if defined(BSD42) || defined(linux) || defined(OSX)
314 if (match(dp->d_name, pattern)) {
315 Gcat(gpath, dp->d_name);
316 #else
317 char dname[DIRSIZ+1];
318 strncpy(dname, dp->d_name, DIRSIZ);
319 if (match(dname, pattern)) {
320 Gcat(gpath, dname);
321 #endif
322 globcnt++;
323 }
324 if (globerr != 0)
325 goto out;
326 }
327 out:
328 #if defined(BSD42) || defined(linux) || defined(OSX)
329 (void)closedir(dirp);
330 #else
331 (void)close(dirf);
332 #endif
333 }
334
335 static int
336 execbrc(char *p, char *s)
337 {
338 char restbuf[BUFSIZ + 2];
339 register char *pe, *pm, *pl;
340 int brclev = 0;
341 char *lm, savec, *sgpathp;
342
343 for (lm = restbuf; *p != '{'; *lm++ = *p++)
344 continue;
345 for (pe = ++p; *pe; pe++)
346 switch (*pe) {
347
348 case '{':
349 brclev++;
350 continue;
351
352 case '}':
353 if (brclev == 0)
354 goto pend;
355 brclev--;
356 continue;
357
358 case '[':
359 for (pe++; *pe && *pe != ']'; pe++)
360 continue;
361 if (!*pe) {
362 globerr = IWC;
363 errstring = MISSBRACK;
364 return (0);
365 }
366 continue;
367 }
368 pend:
369 if (brclev || !*pe) {
370 globerr = IWC;
371 errstring = "Missing } in wild card syntax";
372 return (0);
373 }
374 for (pl = pm = p; pm <= pe; pm++)
375 switch (*pm & (QUOTE|TRIM)) {
376
377 case '{':
378 brclev++;
379 continue;
380
381 case '}':
382 if (brclev) {
383 brclev--;
384 continue;
385 }
386 goto doit;
387
388 case ','|QUOTE:
389 case ',':
390 if (brclev)
391 continue;
392 doit:
393 savec = *pm;
394 *pm = 0;
395 strcpy(lm, pl);
396 strcat(restbuf, pe + 1);
397 *pm = savec;
398 if (s == 0) {
399 sgpathp = gpathp;
400 expand(restbuf);
401 gpathp = sgpathp;
402 *gpathp = 0;
403 } else if (amatch(s, restbuf))
404 return (1);
405 sort();
406 pl = pm + 1;
407 if (brclev)
408 return (0);
409 continue;
410
411 case '[':
412 for (pm++; *pm && *pm != ']'; pm++)
413 continue;
414 if (!*pm) {
415 globerr = IWC;
416 errstring = MISSBRACK;
417 return(0);
418 }
419 continue;
420 }
421 if (brclev && globerr == 0)
422 goto doit;
423 return (0);
424 }
425
426 static int
427 match(char *s, char *p)
428 {
429 register int c;
430 register char *sentp;
431 int sglobbed = globbed;
432
433 /* We don't want this "feature"
434 if (*s == '.' && *p != '.')
435 return (0);
436 */
437 sentp = entp;
438 entp = s;
439 c = amatch(s, p);
440 entp = sentp;
441 globbed = sglobbed;
442 return (c);
443 }
444
445 static int
446 amatch(register char *s, register char *p)
447 {
448 register int scc;
449 int ok, lc;
450 char *sgpathp;
451 struct stat stb;
452 int c, cc;
453
454 globbed = 1;
455 for (;;) {
456 scc = *s++ & TRIM;
457 switch (c = *p++) {
458
459 case '{':
460 return (execbrc(p - 1, s - 1));
461
462 case '[':
463 ok = 0;
464 lc = 077777;
465 while ((cc = *p++)) {
466 if (cc == ']') {
467 if (ok)
468 break;
469 return (0);
470 }
471 if (cc == '-') {
472 if (lc <= scc && scc <= *p++)
473 ok++;
474 } else
475 if (scc == (lc = cc))
476 ok++;
477 }
478 if (cc == 0) {
479 globerr = IWC;
480 errstring = MISSBRACK;
481 return (0);
482 }
483 continue;
484
485 case '*':
486 if (!*p)
487 return (1);
488 if (*p == '/') {
489 p++;
490 goto slash;
491 }
492 s--;
493 do {
494 if (amatch(s, p))
495 return (1);
496 } while (*s++);
497 return (0);
498
499 case 0:
500 return (scc == 0);
501
502 default:
503 if (c != scc)
504 return (0);
505 continue;
506
507 case '?':
508 if (scc == 0)
509 return (0);
510 continue;
511
512 case '/':
513 if (scc)
514 return (0);
515 slash:
516 s = entp;
517 sgpathp = gpathp;
518 while (*s)
519 addpath(*s++);
520 addpath('/');
521 if (stat(gpath, &stb) == 0 && isdir(stb)) {
522 if (*p == 0) {
523 Gcat(gpath, "");
524 globcnt++;
525 } else
526 expand(p);
527 }
528 gpathp = sgpathp;
529 *gpathp = 0;
530 return (0);
531 }
532 }
533 }
534
535 static int
536 Gmatch(register char *s, register char *p)
537 {
538 register int scc;
539 int ok, lc;
540 int c, cc;
541
542 for (;;) {
543 scc = *s++ & TRIM;
544 switch (c = *p++) {
545
546 case '[':
547 ok = 0;
548 lc = 077777;
549 while ((cc = *p++)) {
550 if (cc == ']') {
551 if (ok)
552 break;
553 return (0);
554 }
555 if (cc == '-') {
556 if (lc <= scc && scc <= *p++)
557 ok++;
558 } else
559 if (scc == (lc = cc))
560 ok++;
561 }
562 if (cc == 0) {
563 globerr = IWC;
564 errstring = MISSBRACK;
565 return (0);
566 }
567 continue;
568
569 case '*':
570 if (!*p)
571 return (1);
572 for (s--; *s; s++)
573 if (Gmatch(s, p))
574 return (1);
575 return (0);
576
577 case 0:
578 return (scc == 0);
579
580 default:
581 if ((c & TRIM) != scc)
582 return (0);
583 continue;
584
585 case '?':
586 if (scc == 0)
587 return (0);
588 continue;
589
590 }
591 }
592 }
593
594 static void
595 Gcat(register char *s1, register char *s2)
596 {
597 if (gargc == gargmax) {
598 char **newvec;
599
600 if ((newvec = (char **)malloc((size_t)(gargc + INCVEC + 1) * sizeof(char *))) == (char **)0)
601 fatal(NOMEM);
602 sortbas = newvec + (sortbas - gargv);
603 (void)blkcpy(newvec, gargv);
604 free(gargv);
605 gargv = newvec;
606 gargmax += INCVEC;
607 }
608 gargc++;
609 if (gargv) {
610 gargv[gargc] = 0;
611 gargv[gargc - 1] = strspl(s1, s2);
612 }
613 }
614
615 static void
616 addpath(char c)
617 {
618
619 if (gpathp >= lastgpathp) {
620 globerr = MSC;
621 errstring = "Pathname too long";
622 } else {
623 *gpathp++ = c;
624 *gpathp = 0;
625 }
626 }
627
628 static void
629 rscan(register char **t, int (*f)(char))
630 {
631 register char *p, c;
632
633 while ((p = *t++)) {
634 if (f == tglob) {
635 if (*p == '~')
636 gflag |= 2;
637 else if (eq(p, "{") || eq(p, "{}"))
638 continue;
639 }
640 while ((c = *p++))
641 (*f)(c);
642 }
643 }
644 /*
645 static
646 scan(t, f)
647 register char **t;
648 int (*f)();
649 {
650 register char *p, c;
651
652 while (p = *t++)
653 while (c = *p)
654 *p++ = (*f)(c);
655 }
656 */
657 static int
658 tglob(register char c)
659 {
660
661 if (any(c, globchars))
662 gflag |= c == '{' ? 2 : 1;
663 return (c);
664 }
665 /*
666 static
667 trim(c)
668 char c;
669 {
670
671 return (c & TRIM);
672 }
673 */
674 int
675 letter(register char c)
676 {
677
678 return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
679 }
680
681 int
682 digit(register char c)
683 {
684
685 return (c >= '0' && c <= '9');
686 }
687
688 int
689 any(register int c, register char *s)
690 {
691
692 while (*s)
693 if (*s++ == c)
694 return(1);
695 return(0);
696 }
697
698 int
699 blklen(register char **av)
700 {
701 register int i = 0;
702
703 while (*av++)
704 i++;
705 return (i);
706 }
707
708 char **
709 blkcpy(char **oav, register char **bv)
710 {
711 register char **av = oav;
712
713 if (av)
714 {
715 while ((*av++ = *bv++))
716 continue;
717 }
718 return (oav);
719 }
720
721 void
722 blkfree(char **av0)
723 {
724 register char **av = av0;
725
726 while (*av)
727 free(*av++);
728 free((char *)av0);
729 }
730
731 static char *
732 strspl(char *cp, char *dp)
733 {
734 register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
735
736 if (ep) {
737 strcpy(ep, cp);
738 strcat(ep, dp);
739 }
740 else
741 fatal(NOMEM);
742 return (ep);
743 }
744
745 char **
746 copyblk(register char **v)
747 {
748 if (v == 0)
749 return 0;
750
751 register char **nv = (char **)malloc((size_t)(((size_t)blklen(v) + 1) *
752 sizeof(char **)));
753 if (nv == (char **)0)
754 return 0;
755
756 register char **av = v;
757
758 if (av)
759 {
760 char **bv = nv;
761
762 while (*av)
763 {
764 *bv = malloc(strlen(*av) + 1);
765 if (*bv == 0)
766 {
767 free(nv);
768 return 0;
769 }
770 strcpy(*bv, *av);
771 av++;
772 bv++;
773 }
774 *bv = 0;
775 }
776
777 return nv;
778 }
779
780 static
781 char *
782 strend(cp)
783 register char *cp;
784 {
785
786 while (*cp)
787 cp++;
788 return (cp);
789 }
790 /*
791 * Extract a home directory from the password file
792 * The argument points to a buffer where the name of the
793 * user whose home directory is sought is currently.
794 * We write the home directory of the user back there.
795 */
796 int
797 gethdir(char *homepath)
798 {
799 register struct passwd *pp = getpwnam(homepath);
800
801 if (pp == 0)
802 return (1);
803 strcpy(home, pp->pw_dir);
804 return (0);
805 }

  ViewVC Help
Powered by ViewVC 1.1.5