1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #if 0
19 #ifndef lint
20 static char sccsid[] = "@(#)glob.c	5.7 (Berkeley) 12/14/88";
21 #endif /* not lint */
22 #endif
23 
24 #if HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 
28 /*
29  * C-shell glob for random programs.
30  */
31 
32 
33 #include <sys/param.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <dirent.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <pwd.h>
43 
44 #if !defined(dirfd) && !defined(__GLIBC__) && !defined(__linux__) && \
45     !defined(__FreeBSD__) && !defined(__CYGWIN__) && !defined(__APPLE__) && \
46     !defined(__DragonFly__)
47 #define dirfd(dirp)  ((dirp)->dd_fd)
48 #endif
49 
50 #ifndef NCARGS
51 #define	NCARGS  10240
52 #endif
53 
54 #define	QUOTE 0200
55 #define	TRIM 0177
56 #define	eq(a,b)		(strcmp(a, b)==0)
57 #define	GAVSIZ		(NCARGS/6)
58 #define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
59 
60 static	char **gargv;		/* Pointer to the (stack) arglist */
61 static	int gargc;		/* Number args in gargv */
62 static	int gnleft;
63 static	short gflag;
64 static	int tglob();
65 char	**glob();
66 static  void rscan(char **, int ());
67 static  void ginit(char **);
68 static  void collect(char *);
69 static  void acollect(char *);
70 static  void sort();
71 static  void expand(char *);
72 static  void matchdir(char *);
73 static  int  execbrc(char *, char *);
74 static  int  match(char *, char *);
75 static  int  amatch(char *, char *);
76 #if 0
77 static  int  Gmatch(char *, char *);
78 #endif
79 static  void Gcat(char *, char *);
80 static  void addpath(char);
81 static  void fatal(char *);
82 /*static  void scan(char **, int ());*/
83 char	*globerr;
84 char	*home;
85 struct	passwd *getpwnam();
86 extern	int errno;
87 static	char *strspl(), *strend();
88 /*char	*malloc(), *strcpy(), *strcat(); */
89 char	**copyblk();
90 
91 static	int globcnt;
92 
93 char	*globchars = "`{[*?";
94 
95 static	char *gpath, *gpathp, *lastgpathp;
96 static	int globbed;
97 static	char *entp;
98 static	char **sortbas;
99 
100 void blkfree();
101 int letter();
102 int digit();
103 int gethdir();
104 int any();
105 
106 
107 char **
glob(v)108 glob(v)
109 	char *v;
110 {
111 	char agpath[BUFSIZ];
112 	char *agargv[GAVSIZ];
113 	char *vv[2];
114 	vv[0] = v;
115 	vv[1] = 0;
116 	gflag = 0;
117 	rscan(vv, tglob);
118 	if (gflag == 0)
119 		return (copyblk(vv));
120 
121 	globerr = 0;
122 	gpath = agpath; gpathp = gpath; *gpathp = 0;
123 	lastgpathp = &gpath[sizeof agpath - 2];
124 	ginit(agargv); globcnt = 0;
125 	collect(v);
126 	if (globcnt == 0 && (gflag&1)) {
127 		blkfree(gargv), gargv = 0;
128 		return (0);
129 	} else
130 		return (gargv = copyblk(gargv));
131 }
132 
133 static void
ginit(agargv)134 ginit(agargv)
135 	char **agargv;
136 {
137 
138 	agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
139 	gnleft = NCARGS - 4;
140 }
141 
142 static void
collect(as)143 collect(as)
144 	char *as;
145 {
146 	if (eq(as, "{") || eq(as, "{}")) {
147 		Gcat(as, "");
148 		sort();
149 	} else
150 		acollect(as);
151 }
152 
153 static void
acollect(as)154 acollect(as)
155 	char *as;
156 {
157 	int ogargc = gargc;
158 
159 	gpathp = gpath; *gpathp = 0; globbed = 0;
160 	expand(as);
161 	if (gargc != ogargc)
162 		sort();
163 }
164 
165 static void
sort()166 sort()
167 {
168 	char **p1, **p2, *c;
169 	char **Gvp = &gargv[gargc];
170 
171 	p1 = sortbas;
172 	while (p1 < Gvp-1) {
173 		p2 = p1;
174 		while (++p2 < Gvp)
175 			if (strcmp(*p1, *p2) > 0)
176 				c = *p1, *p1 = *p2, *p2 = c;
177 		p1++;
178 	}
179 	sortbas = Gvp;
180 }
181 
182 static void
expand(as)183 expand(as)
184 	char *as;
185 {
186 	char *cs;
187 	char *sgpathp, *oldcs;
188 	struct stat stb;
189 
190 	sgpathp = gpathp;
191 	cs = as;
192 	if (*cs == '~' && gpathp == gpath) {
193 		addpath('~');
194 		for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
195 			addpath(*cs++);
196 		if (!*cs || *cs == '/') {
197 			if (gpathp != gpath + 1) {
198 				*gpathp = 0;
199 				if (gethdir(gpath + 1))
200 					globerr = "Unknown user name after ~";
201 				(void) strcpy(gpath, gpath + 1);
202 			} else {
203 				if(home == NULL) {
204 				    struct passwd *pp;
205 				    extern char *getenv();
206 
207 				    home = getenv("HOME");
208 				    if(home == NULL) {
209 					pp = getpwuid(getuid());
210 					if(pp != NULL)
211 					    home = pp->pw_dir;
212 				    }
213 				}
214 				if(home == NULL) {
215 				    home = "";
216 				    globerr = "Can't determine own home directory";
217 				} else {
218 				    (void) strcpy(gpath, home);
219 				}
220 			}
221 			gpathp = strend(gpath);
222 		}
223 	}
224 	while (!any(*cs, globchars)) {
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
matchdir(pattern)253 matchdir(pattern)
254 	char *pattern;
255 {
256 	struct stat stb;
257 	struct dirent *dp;
258 	DIR *dirp;
259 
260 	dirp = opendir(gpath[0] == '\0' ? "." : gpath);
261 	if (dirp == NULL) {
262 		if (globbed)
263 			return;
264 		goto patherr2;
265 	}
266 	if (fstat(dirfd(dirp), &stb) < 0)
267 		goto patherr1;
268 	if (!isdir(stb)) {
269 		errno = ENOTDIR;
270 		goto patherr1;
271 	}
272 	while ((dp = readdir(dirp)) != NULL) {
273 		if (dp->d_ino == 0)
274 			continue;
275 		if (match(dp->d_name, pattern)) {
276 			Gcat(gpath, dp->d_name);
277 			globcnt++;
278 		}
279 	}
280 	closedir(dirp);
281 	return;
282 
283 patherr1:
284 	closedir(dirp);
285 patherr2:
286 	globerr = "Bad directory components";
287 }
288 
289 static int
execbrc(p,s)290 execbrc(p, s)
291 	char *p, *s;
292 {
293 	char restbuf[BUFSIZ + 2];
294 	char *pe, *pm, *pl;
295 	int brclev = 0;
296 	char *lm, savec, *sgpathp;
297 
298 	for (lm = restbuf; *p != '{'; *lm++ = *p++)
299 		continue;
300 	for (pe = ++p; *pe; pe++)
301 	switch (*pe) {
302 
303 	case '{':
304 		brclev++;
305 		continue;
306 
307 	case '}':
308 		if (brclev == 0)
309 			goto pend;
310 		brclev--;
311 		continue;
312 
313 	case '[':
314 		for (pe++; *pe && *pe != ']'; pe++)
315 			continue;
316 		continue;
317 	}
318 pend:
319 	brclev = 0;
320 	for (pl = pm = p; pm <= pe; pm++)
321 	switch (*pm & (QUOTE|TRIM)) {
322 
323 	case '{':
324 		brclev++;
325 		continue;
326 
327 	case '}':
328 		if (brclev) {
329 			brclev--;
330 			continue;
331 		}
332 		goto doit;
333 
334 	case ','|QUOTE:
335 	case ',':
336 		if (brclev)
337 			continue;
338 doit:
339 		savec = *pm;
340 		*pm = 0;
341 		(void) strcpy(lm, pl);
342 		(void) strcat(restbuf, pe + 1);
343 		*pm = savec;
344 		if (s == 0) {
345 			sgpathp = gpathp;
346 			expand(restbuf);
347 			gpathp = sgpathp;
348 			*gpathp = 0;
349 		} else if (amatch(s, restbuf))
350 			return (1);
351 		sort();
352 		pl = pm + 1;
353 		if (brclev)
354 			return (0);
355 		continue;
356 
357 	case '[':
358 		for (pm++; *pm && *pm != ']'; pm++)
359 			continue;
360 		if (!*pm)
361 			pm--;
362 		continue;
363 	}
364 	if (brclev)
365 		goto doit;
366 	return (0);
367 }
368 
369 static int
match(s,p)370 match(s, p)
371 	char *s, *p;
372 {
373 	int c;
374 	char *sentp;
375 	char sglobbed = globbed;
376 
377 	if (*s == '.' && *p != '.')
378 		return (0);
379 	sentp = entp;
380 	entp = s;
381 	c = amatch(s, p);
382 	entp = sentp;
383 	globbed = sglobbed;
384 	return (c);
385 }
386 
387 static int
amatch(s,p)388 amatch(s, p)
389 	char *s, *p;
390 {
391 	int scc;
392 	int ok, lc;
393 	char *sgpathp;
394 	struct stat stb;
395 	int c, cc;
396 
397 	globbed = 1;
398 	for (;;) {
399 		scc = *s++ & TRIM;
400 		switch (c = *p++) {
401 
402 		case '{':
403 			return (execbrc(p - 1, s - 1));
404 
405 		case '[':
406 			ok = 0;
407 			lc = 077777;
408 			while ((cc = *p++)) {
409 				if (cc == ']') {
410 					if (ok)
411 						break;
412 					return (0);
413 				}
414 				if (cc == '-') {
415 					if (lc <= scc && scc <= *p++)
416 						ok++;
417 				} else
418 					if (scc == (lc = cc))
419 						ok++;
420 			}
421 			if ((cc == 0)) {
422 			  if (ok) {
423 			    p--;
424 			  } else {
425 			    return 0;
426 			  }
427 			}
428 			continue;
429 
430 		case '*':
431 			if (!*p)
432 				return (1);
433 			if (*p == '/') {
434 				p++;
435 				goto slash;
436 			}
437 			s--;
438 			do {
439 				if (amatch(s, p))
440 					return (1);
441 			} while (*s++);
442 			return (0);
443 
444 		case 0:
445 			return (scc == 0);
446 
447 		default:
448 			if (c != scc)
449 				return (0);
450 			continue;
451 
452 		case '?':
453 			if (scc == 0)
454 				return (0);
455 			continue;
456 
457 		case '/':
458 			if (scc)
459 				return (0);
460 slash:
461 			s = entp;
462 			sgpathp = gpathp;
463 			while (*s)
464 				addpath(*s++);
465 			addpath('/');
466 			if (stat(gpath, &stb) == 0 && isdir(stb)) {
467 				if (*p == 0) {
468 					Gcat(gpath, "");
469 					globcnt++;
470 				} else {
471 					expand(p);
472 				}
473 			}
474 			gpathp = sgpathp;
475 			*gpathp = 0;
476 			return (0);
477 		}
478 	}
479 }
480 
481 #if 0
482 static int
483 Gmatch(s, p)
484 	char *s, *p;
485 {
486 	int scc;
487 	int ok, lc;
488 	int c, cc;
489 
490 	for (;;) {
491 		scc = *s++ & TRIM;
492 		switch (c = *p++) {
493 
494 		case '[':
495 			ok = 0;
496 			lc = 077777;
497 			while ((cc = *p++)) {
498 				if (cc == ']') {
499 					if (ok)
500 						break;
501 					return (0);
502 				}
503 				if (cc == '-') {
504 					if (lc <= scc && scc <= *p++)
505 						ok++;
506 				} else
507 					if (scc == (lc = cc))
508 						ok++;
509 			}
510 			if ((cc == 0)) {
511 			  if (ok) {
512 			    p--;
513 			  } else {
514 			    return 0;
515 			  }
516 			}
517 			continue;
518 
519 		case '*':
520 			if (!*p)
521 				return (1);
522 			for (s--; *s; s++)
523 				if (Gmatch(s, p))
524 					return (1);
525 			return (0);
526 
527 		case 0:
528 			return (scc == 0);
529 
530 		default:
531 			if ((c & TRIM) != scc)
532 				return (0);
533 			continue;
534 
535 		case '?':
536 			if (scc == 0)
537 				return (0);
538 			continue;
539 
540 		}
541 	}
542 }
543 #endif
544 
545 static void
Gcat(s1,s2)546 Gcat(s1, s2)
547 	char *s1, *s2;
548 {
549 	int len = strlen(s1) + strlen(s2) + 1;
550 
551 	if (len >= gnleft || gargc >= GAVSIZ - 1)
552 		globerr = "Arguments too long";
553 	else {
554 		gargc++;
555 		gnleft -= len;
556 		gargv[gargc] = 0;
557 		gargv[gargc - 1] = strspl(s1, s2);
558 	}
559 }
560 
561 static void
addpath(char c)562 addpath(char c)
563 {
564 
565 	if (gpathp >= lastgpathp)
566 		globerr = "Pathname too long";
567 	else {
568 		*gpathp++ = c;
569 		*gpathp = 0;
570 	}
571 }
572 
573 static void
rscan(t,f)574 rscan(t, f)
575 	char **t;
576 	int (*f)();
577 {
578 	char *p, c;
579 
580 	while ((p = *t++)) {
581 	  if (f == tglob) {
582 	    if (*p == '~') {
583 	      gflag |= 2;
584 	    } else if (eq(p, "{") || eq(p, "{}")) {
585 	      continue;
586 	    }
587 	  }
588 		while ((c = *p++))
589 			(*f)(c);
590 	}
591 }
592 /*
593 static void
594 scan(t, f)
595 	char **t;
596 	int (*f)();
597 {
598 	char *p, c;
599 
600 	while (p = *t++)
601 		while (c = *p)
602 			*p++ = (*f)(c);
603 } */
604 
605 static int
tglob(c)606 tglob(c)
607 	char c;
608 {
609 
610 	if (any(c, globchars))
611 		gflag |= c == '{' ? 2 : 1;
612 	return (c);
613 }
614 /*
615 static void
616 trim(c)
617 	char c;
618 {
619 
620 	return (c & TRIM);
621 } */
622 
623 
624 int
letter(c)625 letter(c)
626 	char c;
627 {
628 
629 	return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
630 }
631 
632 int
digit(c)633 digit(c)
634 	char c;
635 {
636 
637 	return (c >= '0' && c <= '9');
638 }
639 
640 int
any(c,s)641 any(c, s)
642 	int c;
643 	char *s;
644 {
645 
646 	while (*s)
647 		if (*s++ == c)
648 			return(1);
649 	return(0);
650 }
651 
652 int
blklen(av)653 blklen(av)
654 	char **av;
655 {
656 	int i = 0;
657 
658 	while (*av++)
659 		i++;
660 	return (i);
661 }
662 
663 char **
blkcpy(oav,bv)664 blkcpy(oav, bv)
665 	char **oav;
666 	char **bv;
667 {
668 	char **av = oav;
669 
670 	while ((*av++ = *bv++))
671 		continue;
672 	return (oav);
673 }
674 
675 void
blkfree(av0)676 blkfree(av0)
677 	char **av0;
678 {
679 	char **av = av0;
680 
681 	while (*av)
682 		free(*av++);
683 }
684 
685 static
686 char *
strspl(cp,dp)687 strspl(cp, dp)
688 	char *cp, *dp;
689 {
690 	char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
691 
692 	if (ep == (char *)0)
693 		fatal("Out of memory");
694 	(void) strcpy(ep, cp);
695 	(void) strcat(ep, dp);
696 	return (ep);
697 }
698 
699 char **
copyblk(v)700 copyblk(v)
701 	char **v;
702 {
703 	char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
704 						sizeof(char **)));
705 	if (nv == (char **)0)
706 		fatal("Out of memory");
707 
708 	return (blkcpy(nv, v));
709 }
710 
711 static
712 char *
strend(cp)713 strend(cp)
714 	char *cp;
715 {
716 
717 	while (*cp)
718 		cp++;
719 	return (cp);
720 }
721 /*
722  * Extract a home directory from the password file
723  * The argument points to a buffer where the name of the
724  * user whose home directory is sought is currently.
725  * We write the home directory of the user back there.
726  */
727 int
gethdir(home)728 gethdir(home)
729 	char *home;
730 {
731 	struct passwd *pp = getpwnam(home);
732 
733 	if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
734 		return (1);
735 	(void) strcpy(home, pp->pw_dir);
736 	return (0);
737 }
738 
739 static void
fatal(s)740 fatal(s)
741 char *s;
742 {
743     fprintf( stderr, "glob: %s\n", s );
744     exit(1);
745 }
746