xref: /plan9/sys/src/cmd/rc/glob.c (revision 99eb86a7eded05d02373a1dc66f01c7d211105e0)
13e12c5d1SDavid du Colombier #include "rc.h"
23e12c5d1SDavid du Colombier #include "exec.h"
33e12c5d1SDavid du Colombier #include "fns.h"
43e12c5d1SDavid du Colombier char *globname;
53e12c5d1SDavid du Colombier struct word *globv;
63e12c5d1SDavid du Colombier /*
73e12c5d1SDavid du Colombier  * delete all the GLOB marks from s, in place
83e12c5d1SDavid du Colombier  */
9dc5a79c1SDavid du Colombier 
10dc5a79c1SDavid du Colombier void
11276e7d6dSDavid du Colombier deglob(void *as)
123e12c5d1SDavid du Colombier {
13276e7d6dSDavid du Colombier 	char *s = as;
143e12c5d1SDavid du Colombier 	char *t = s;
153e12c5d1SDavid du Colombier 	do{
16dc5a79c1SDavid du Colombier 		if(*t==GLOB)
17dc5a79c1SDavid du Colombier 			t++;
183e12c5d1SDavid du Colombier 		*s++=*t;
193e12c5d1SDavid du Colombier 	}while(*t++);
203e12c5d1SDavid du Colombier }
21dc5a79c1SDavid du Colombier 
22dc5a79c1SDavid du Colombier int
23dc5a79c1SDavid du Colombier globcmp(const void *s, const void *t)
243e12c5d1SDavid du Colombier {
257dd7cddfSDavid du Colombier 	return strcmp(*(char**)s, *(char**)t);
263e12c5d1SDavid du Colombier }
27dc5a79c1SDavid du Colombier 
28dc5a79c1SDavid du Colombier void
29dc5a79c1SDavid du Colombier globsort(word *left, word *right)
303e12c5d1SDavid du Colombier {
313e12c5d1SDavid du Colombier 	char **list;
323e12c5d1SDavid du Colombier 	word *a;
333e12c5d1SDavid du Colombier 	int n = 0;
34*99eb86a7SDavid du Colombier 	for(a = left;a!=right;a = a->next) n++;
353e12c5d1SDavid du Colombier 	list = (char **)emalloc(n*sizeof(char *));
36*99eb86a7SDavid du Colombier 	for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
37dc5a79c1SDavid du Colombier 	qsort((void *)list, n, sizeof(void *), globcmp);
38*99eb86a7SDavid du Colombier 	for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
393e12c5d1SDavid du Colombier 	efree((char *)list);
403e12c5d1SDavid du Colombier }
413e12c5d1SDavid du Colombier /*
423e12c5d1SDavid du Colombier  * Push names prefixed by globname and suffixed by a match of p onto the astack.
433e12c5d1SDavid du Colombier  * namep points to the end of the prefix in globname.
443e12c5d1SDavid du Colombier  */
45dc5a79c1SDavid du Colombier 
46dc5a79c1SDavid du Colombier void
47276e7d6dSDavid du Colombier globdir(uchar *p, uchar *namep)
483e12c5d1SDavid du Colombier {
49276e7d6dSDavid du Colombier 	uchar *t, *newp;
503e12c5d1SDavid du Colombier 	int f;
513e12c5d1SDavid du Colombier 	/* scan the pattern looking for a component with a metacharacter in it */
523e12c5d1SDavid du Colombier 	if(*p=='\0'){
533e12c5d1SDavid du Colombier 		globv = newword(globname, globv);
543e12c5d1SDavid du Colombier 		return;
553e12c5d1SDavid du Colombier 	}
563e12c5d1SDavid du Colombier 	t = namep;
573e12c5d1SDavid du Colombier 	newp = p;
583e12c5d1SDavid du Colombier 	while(*newp){
593e12c5d1SDavid du Colombier 		if(*newp==GLOB)
603e12c5d1SDavid du Colombier 			break;
613e12c5d1SDavid du Colombier 		*t=*newp++;
623e12c5d1SDavid du Colombier 		if(*t++=='/'){
633e12c5d1SDavid du Colombier 			namep = t;
643e12c5d1SDavid du Colombier 			p = newp;
653e12c5d1SDavid du Colombier 		}
663e12c5d1SDavid du Colombier 	}
673e12c5d1SDavid du Colombier 	/* If we ran out of pattern, append the name if accessible */
683e12c5d1SDavid du Colombier 	if(*newp=='\0'){
693e12c5d1SDavid du Colombier 		*t='\0';
703e12c5d1SDavid du Colombier 		if(access(globname, 0)==0)
713e12c5d1SDavid du Colombier 			globv = newword(globname, globv);
723e12c5d1SDavid du Colombier 		return;
733e12c5d1SDavid du Colombier 	}
743e12c5d1SDavid du Colombier 	/* read the directory and recur for any entry that matches */
753e12c5d1SDavid du Colombier 	*namep='\0';
76*99eb86a7SDavid du Colombier 	if((f = Opendir(globname[0]?globname:"."))<0) return;
77*99eb86a7SDavid du Colombier 	while(*newp!='/' && *newp!='\0') newp++;
786b6b9ac8SDavid du Colombier 	while(Readdir(f, namep, *newp=='/')){
793e12c5d1SDavid du Colombier 		if(matchfn(namep, p)){
80*99eb86a7SDavid du Colombier 			for(t = namep;*t;t++);
813e12c5d1SDavid du Colombier 			globdir(newp, t);
823e12c5d1SDavid du Colombier 		}
833e12c5d1SDavid du Colombier 	}
843e12c5d1SDavid du Colombier 	Closedir(f);
853e12c5d1SDavid du Colombier }
863e12c5d1SDavid du Colombier /*
873e12c5d1SDavid du Colombier  * Push all file names matched by p on the current thread's stack.
883e12c5d1SDavid du Colombier  * If there are no matches, the list consists of p.
893e12c5d1SDavid du Colombier  */
90dc5a79c1SDavid du Colombier 
91dc5a79c1SDavid du Colombier void
92276e7d6dSDavid du Colombier glob(void *ap)
933e12c5d1SDavid du Colombier {
94276e7d6dSDavid du Colombier 	uchar *p = ap;
953e12c5d1SDavid du Colombier 	word *svglobv = globv;
96276e7d6dSDavid du Colombier 	int globlen = Globsize(ap);
97276e7d6dSDavid du Colombier 
983e12c5d1SDavid du Colombier 	if(!globlen){
993e12c5d1SDavid du Colombier 		deglob(p);
100276e7d6dSDavid du Colombier 		globv = newword((char *)p, globv);
1013e12c5d1SDavid du Colombier 		return;
1023e12c5d1SDavid du Colombier 	}
1033e12c5d1SDavid du Colombier 	globname = emalloc(globlen);
1043e12c5d1SDavid du Colombier 	globname[0]='\0';
105276e7d6dSDavid du Colombier 	globdir(p, (uchar *)globname);
1063e12c5d1SDavid du Colombier 	efree(globname);
1073e12c5d1SDavid du Colombier 	if(svglobv==globv){
1083e12c5d1SDavid du Colombier 		deglob(p);
109276e7d6dSDavid du Colombier 		globv = newword((char *)p, globv);
1103e12c5d1SDavid du Colombier 	}
1113e12c5d1SDavid du Colombier 	else
1123e12c5d1SDavid du Colombier 		globsort(globv, svglobv);
1133e12c5d1SDavid du Colombier }
1143e12c5d1SDavid du Colombier /*
1153e12c5d1SDavid du Colombier  * Do p and q point at equal utf codes
1163e12c5d1SDavid du Colombier  */
117dc5a79c1SDavid du Colombier 
118dc5a79c1SDavid du Colombier int
119276e7d6dSDavid du Colombier equtf(uchar *p, uchar *q)
120dc5a79c1SDavid du Colombier {
121dc5a79c1SDavid du Colombier 	if(*p!=*q)
122dc5a79c1SDavid du Colombier 		return 0;
123*99eb86a7SDavid du Colombier 	if(twobyte(*p)) return p[1]==q[1];
1243e12c5d1SDavid du Colombier 	if(threebyte(*p)){
125dc5a79c1SDavid du Colombier 		if(p[1]!=q[1])
126dc5a79c1SDavid du Colombier 			return 0;
127dc5a79c1SDavid du Colombier 		if(p[1]=='\0')
128dc5a79c1SDavid du Colombier 			return 1;	/* broken code at end of string! */
1293e12c5d1SDavid du Colombier 		return p[2]==q[2];
1303e12c5d1SDavid du Colombier 	}
1313e12c5d1SDavid du Colombier 	return 1;
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier /*
1343e12c5d1SDavid du Colombier  * Return a pointer to the next utf code in the string,
1353e12c5d1SDavid du Colombier  * not jumping past nuls in broken utf codes!
1363e12c5d1SDavid du Colombier  */
137dc5a79c1SDavid du Colombier 
138276e7d6dSDavid du Colombier uchar*
139276e7d6dSDavid du Colombier nextutf(uchar *p)
140dc5a79c1SDavid du Colombier {
141*99eb86a7SDavid du Colombier 	if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
142*99eb86a7SDavid du Colombier 	if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
1433e12c5d1SDavid du Colombier 	return p+1;
1443e12c5d1SDavid du Colombier }
1453e12c5d1SDavid du Colombier /*
1463e12c5d1SDavid du Colombier  * Convert the utf code at *p to a unicode value
1473e12c5d1SDavid du Colombier  */
148dc5a79c1SDavid du Colombier 
149dc5a79c1SDavid du Colombier int
150276e7d6dSDavid du Colombier unicode(uchar *p)
151dc5a79c1SDavid du Colombier {
152276e7d6dSDavid du Colombier 	int u = *p;
153276e7d6dSDavid du Colombier 
154276e7d6dSDavid du Colombier 	if(twobyte(u))
155276e7d6dSDavid du Colombier 		return ((u&0x1f)<<6)|(p[1]&0x3f);
156276e7d6dSDavid du Colombier 	if(threebyte(u))
157276e7d6dSDavid du Colombier 		return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
1583e12c5d1SDavid du Colombier 	return u;
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier /*
1613e12c5d1SDavid du Colombier  * Does the string s match the pattern p
1623e12c5d1SDavid du Colombier  * . and .. are only matched by patterns starting with .
1633e12c5d1SDavid du Colombier  * * matches any sequence of characters
1643e12c5d1SDavid du Colombier  * ? matches any single character
1653e12c5d1SDavid du Colombier  * [...] matches the enclosed list of characters
1663e12c5d1SDavid du Colombier  */
167dc5a79c1SDavid du Colombier 
168dc5a79c1SDavid du Colombier int
169276e7d6dSDavid du Colombier matchfn(void *as, void *ap)
1703e12c5d1SDavid du Colombier {
171276e7d6dSDavid du Colombier 	uchar *s = as, *p = ap;
172276e7d6dSDavid du Colombier 
1733e12c5d1SDavid du Colombier 	if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
1743e12c5d1SDavid du Colombier 		return 0;
1753e12c5d1SDavid du Colombier 	return match(s, p, '/');
1763e12c5d1SDavid du Colombier }
177dc5a79c1SDavid du Colombier 
178dc5a79c1SDavid du Colombier int
179276e7d6dSDavid du Colombier match(void *as, void *ap, int stop)
1803e12c5d1SDavid du Colombier {
1813e12c5d1SDavid du Colombier 	int compl, hit, lo, hi, t, c;
182276e7d6dSDavid du Colombier 	uchar *s = as, *p = ap;
183276e7d6dSDavid du Colombier 
1843e12c5d1SDavid du Colombier 	for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){
1853e12c5d1SDavid du Colombier 		if(*p!=GLOB){
1863e12c5d1SDavid du Colombier 			if(!equtf(p, s)) return 0;
1873e12c5d1SDavid du Colombier 		}
1883e12c5d1SDavid du Colombier 		else switch(*++p){
1893e12c5d1SDavid du Colombier 		case GLOB:
190dc5a79c1SDavid du Colombier 			if(*s!=GLOB)
191dc5a79c1SDavid du Colombier 				return 0;
1923e12c5d1SDavid du Colombier 			break;
1933e12c5d1SDavid du Colombier 		case '*':
1943e12c5d1SDavid du Colombier 			for(;;){
1953e12c5d1SDavid du Colombier 				if(match(s, nextutf(p), stop)) return 1;
196dc5a79c1SDavid du Colombier 				if(!*s)
197dc5a79c1SDavid du Colombier 					break;
1983e12c5d1SDavid du Colombier 				s = nextutf(s);
1993e12c5d1SDavid du Colombier 			}
2003e12c5d1SDavid du Colombier 			return 0;
2013e12c5d1SDavid du Colombier 		case '?':
202dc5a79c1SDavid du Colombier 			if(*s=='\0')
203dc5a79c1SDavid du Colombier 				return 0;
2043e12c5d1SDavid du Colombier 			break;
2053e12c5d1SDavid du Colombier 		case '[':
206dc5a79c1SDavid du Colombier 			if(*s=='\0')
207dc5a79c1SDavid du Colombier 				return 0;
2083e12c5d1SDavid du Colombier 			c = unicode(s);
2093e12c5d1SDavid du Colombier 			p++;
2103e12c5d1SDavid du Colombier 			compl=*p=='~';
211dc5a79c1SDavid du Colombier 			if(compl)
212dc5a79c1SDavid du Colombier 				p++;
2133e12c5d1SDavid du Colombier 			hit = 0;
2143e12c5d1SDavid du Colombier 			while(*p!=']'){
215dc5a79c1SDavid du Colombier 				if(*p=='\0')
216dc5a79c1SDavid du Colombier 					return 0;		/* syntax error */
2173e12c5d1SDavid du Colombier 				lo = unicode(p);
2183e12c5d1SDavid du Colombier 				p = nextutf(p);
219dc5a79c1SDavid du Colombier 				if(*p!='-')
220dc5a79c1SDavid du Colombier 					hi = lo;
2213e12c5d1SDavid du Colombier 				else{
2223e12c5d1SDavid du Colombier 					p++;
223dc5a79c1SDavid du Colombier 					if(*p=='\0')
224dc5a79c1SDavid du Colombier 						return 0;	/* syntax error */
2253e12c5d1SDavid du Colombier 					hi = unicode(p);
2263e12c5d1SDavid du Colombier 					p = nextutf(p);
2273e12c5d1SDavid du Colombier 					if(hi<lo){ t = lo; lo = hi; hi = t; }
2283e12c5d1SDavid du Colombier 				}
229dc5a79c1SDavid du Colombier 				if(lo<=c && c<=hi)
230dc5a79c1SDavid du Colombier 					hit = 1;
2313e12c5d1SDavid du Colombier 			}
232dc5a79c1SDavid du Colombier 			if(compl)
233dc5a79c1SDavid du Colombier 				hit=!hit;
234dc5a79c1SDavid du Colombier 			if(!hit)
235dc5a79c1SDavid du Colombier 				return 0;
2363e12c5d1SDavid du Colombier 			break;
2373e12c5d1SDavid du Colombier 		}
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	return *s=='\0';
2403e12c5d1SDavid du Colombier }
241dc5a79c1SDavid du Colombier 
242dc5a79c1SDavid du Colombier void
243dc5a79c1SDavid du Colombier globlist1(word *gl)
2443e12c5d1SDavid du Colombier {
2453e12c5d1SDavid du Colombier 	if(gl){
2463e12c5d1SDavid du Colombier 		globlist1(gl->next);
2473e12c5d1SDavid du Colombier 		glob(gl->word);
2483e12c5d1SDavid du Colombier 	}
2493e12c5d1SDavid du Colombier }
250dc5a79c1SDavid du Colombier 
251dc5a79c1SDavid du Colombier void
252dc5a79c1SDavid du Colombier globlist(void)
253dc5a79c1SDavid du Colombier {
2543e12c5d1SDavid du Colombier 	word *a;
2553e12c5d1SDavid du Colombier 	globv = 0;
2563e12c5d1SDavid du Colombier 	globlist1(runq->argv->words);
2573e12c5d1SDavid du Colombier 	poplist();
2583e12c5d1SDavid du Colombier 	pushlist();
2593e12c5d1SDavid du Colombier 	if(globv){
2603e12c5d1SDavid du Colombier 		for(a = globv;a->next;a = a->next);
2613e12c5d1SDavid du Colombier 		a->next = runq->argv->words;
2623e12c5d1SDavid du Colombier 		runq->argv->words = globv;
2633e12c5d1SDavid du Colombier 	}
2643e12c5d1SDavid du Colombier }
265