xref: /plan9/sys/src/cmd/rc/glob.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include "rc.h"
2*3e12c5d1SDavid du Colombier #include "exec.h"
3*3e12c5d1SDavid du Colombier #include "fns.h"
4*3e12c5d1SDavid du Colombier char *globname;
5*3e12c5d1SDavid du Colombier struct word *globv;
6*3e12c5d1SDavid du Colombier /*
7*3e12c5d1SDavid du Colombier  * delete all the GLOB marks from s, in place
8*3e12c5d1SDavid du Colombier  */
9*3e12c5d1SDavid du Colombier void deglob(char *s)
10*3e12c5d1SDavid du Colombier {
11*3e12c5d1SDavid du Colombier 	char *t=s;
12*3e12c5d1SDavid du Colombier 	do{
13*3e12c5d1SDavid du Colombier 		if(*t==GLOB) t++;
14*3e12c5d1SDavid du Colombier 		*s++=*t;
15*3e12c5d1SDavid du Colombier 	}while(*t++);
16*3e12c5d1SDavid du Colombier }
17*3e12c5d1SDavid du Colombier int globcmp(char **s, char **t)
18*3e12c5d1SDavid du Colombier {
19*3e12c5d1SDavid du Colombier 	return strcmp(*s, *t);
20*3e12c5d1SDavid du Colombier }
21*3e12c5d1SDavid du Colombier void globsort(word *left, word *right)
22*3e12c5d1SDavid du Colombier {
23*3e12c5d1SDavid du Colombier 	char **list;
24*3e12c5d1SDavid du Colombier 	word *a;
25*3e12c5d1SDavid du Colombier 	int n=0;
26*3e12c5d1SDavid du Colombier 	for(a=left;a!=right;a=a->next) n++;
27*3e12c5d1SDavid du Colombier 	list=(char **)emalloc(n*sizeof(char *));
28*3e12c5d1SDavid du Colombier 	for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
29*3e12c5d1SDavid du Colombier 	qsort((char *)list, n, sizeof(char *), globcmp);
30*3e12c5d1SDavid du Colombier 	for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
31*3e12c5d1SDavid du Colombier 	efree((char *)list);
32*3e12c5d1SDavid du Colombier }
33*3e12c5d1SDavid du Colombier /*
34*3e12c5d1SDavid du Colombier  * Push names prefixed by globname and suffixed by a match of p onto the astack.
35*3e12c5d1SDavid du Colombier  * namep points to the end of the prefix in globname.
36*3e12c5d1SDavid du Colombier  */
37*3e12c5d1SDavid du Colombier void globdir(char *p, char *namep)
38*3e12c5d1SDavid du Colombier {
39*3e12c5d1SDavid du Colombier 	char *t, *newp;
40*3e12c5d1SDavid du Colombier 	int f;
41*3e12c5d1SDavid du Colombier 	/* scan the pattern looking for a component with a metacharacter in it */
42*3e12c5d1SDavid du Colombier 	if(*p=='\0'){
43*3e12c5d1SDavid du Colombier 		globv=newword(globname, globv);
44*3e12c5d1SDavid du Colombier 		return;
45*3e12c5d1SDavid du Colombier 	}
46*3e12c5d1SDavid du Colombier 	t=namep;
47*3e12c5d1SDavid du Colombier 	newp=p;
48*3e12c5d1SDavid du Colombier 	while(*newp){
49*3e12c5d1SDavid du Colombier 		if(*newp==GLOB)
50*3e12c5d1SDavid du Colombier 			break;
51*3e12c5d1SDavid du Colombier 		*t=*newp++;
52*3e12c5d1SDavid du Colombier 		if(*t++=='/'){
53*3e12c5d1SDavid du Colombier 			namep=t;
54*3e12c5d1SDavid du Colombier 			p=newp;
55*3e12c5d1SDavid du Colombier 		}
56*3e12c5d1SDavid du Colombier 	}
57*3e12c5d1SDavid du Colombier 	/* If we ran out of pattern, append the name if accessible */
58*3e12c5d1SDavid du Colombier 	if(*newp=='\0'){
59*3e12c5d1SDavid du Colombier 		*t='\0';
60*3e12c5d1SDavid du Colombier 		if(access(globname, 0)==0)
61*3e12c5d1SDavid du Colombier 			globv=newword(globname, globv);
62*3e12c5d1SDavid du Colombier 		return;
63*3e12c5d1SDavid du Colombier 	}
64*3e12c5d1SDavid du Colombier 	/* read the directory and recur for any entry that matches */
65*3e12c5d1SDavid du Colombier 	*namep='\0';
66*3e12c5d1SDavid du Colombier 	if((f=Opendir(globname[0]?globname:"."))<0) return;
67*3e12c5d1SDavid du Colombier 	while(*newp!='/' && *newp!='\0') newp++;
68*3e12c5d1SDavid du Colombier 	while(Readdir(f, namep)){
69*3e12c5d1SDavid du Colombier 		if(matchfn(namep, p)){
70*3e12c5d1SDavid du Colombier 			for(t=namep;*t;t++);
71*3e12c5d1SDavid du Colombier 			globdir(newp, t);
72*3e12c5d1SDavid du Colombier 		}
73*3e12c5d1SDavid du Colombier 	}
74*3e12c5d1SDavid du Colombier 	Closedir(f);
75*3e12c5d1SDavid du Colombier }
76*3e12c5d1SDavid du Colombier /*
77*3e12c5d1SDavid du Colombier  * Push all file names matched by p on the current thread's stack.
78*3e12c5d1SDavid du Colombier  * If there are no matches, the list consists of p.
79*3e12c5d1SDavid du Colombier  */
80*3e12c5d1SDavid du Colombier void glob(char *p)
81*3e12c5d1SDavid du Colombier {
82*3e12c5d1SDavid du Colombier 	word *svglobv=globv;
83*3e12c5d1SDavid du Colombier 	int globlen=Globsize(p);
84*3e12c5d1SDavid du Colombier 	if(!globlen){
85*3e12c5d1SDavid du Colombier 		deglob(p);
86*3e12c5d1SDavid du Colombier 		globv=newword(p, globv);
87*3e12c5d1SDavid du Colombier 		return;
88*3e12c5d1SDavid du Colombier 	}
89*3e12c5d1SDavid du Colombier 	globname=emalloc(globlen);
90*3e12c5d1SDavid du Colombier 	globname[0]='\0';
91*3e12c5d1SDavid du Colombier 	globdir(p, globname);
92*3e12c5d1SDavid du Colombier 	efree(globname);
93*3e12c5d1SDavid du Colombier 	if(svglobv==globv){
94*3e12c5d1SDavid du Colombier 		deglob(p);
95*3e12c5d1SDavid du Colombier 		globv=newword(p, globv);
96*3e12c5d1SDavid du Colombier 	}
97*3e12c5d1SDavid du Colombier 	else
98*3e12c5d1SDavid du Colombier 		globsort(globv, svglobv);
99*3e12c5d1SDavid du Colombier }
100*3e12c5d1SDavid du Colombier /*
101*3e12c5d1SDavid du Colombier  * Do p and q point at equal utf codes
102*3e12c5d1SDavid du Colombier  */
103*3e12c5d1SDavid du Colombier int equtf(char *p, char *q){
104*3e12c5d1SDavid du Colombier 	if(*p!=*q) return 0;
105*3e12c5d1SDavid du Colombier 	if(twobyte(*p)) return p[1]==q[1];
106*3e12c5d1SDavid du Colombier 	if(threebyte(*p)){
107*3e12c5d1SDavid du Colombier 		if(p[1]!=q[1]) return 0;
108*3e12c5d1SDavid du Colombier 		if(p[1]=='\0') return 1;	/* broken code at end of string! */
109*3e12c5d1SDavid du Colombier 		return p[2]==q[2];
110*3e12c5d1SDavid du Colombier 	}
111*3e12c5d1SDavid du Colombier 	return 1;
112*3e12c5d1SDavid du Colombier }
113*3e12c5d1SDavid du Colombier /*
114*3e12c5d1SDavid du Colombier  * Return a pointer to the next utf code in the string,
115*3e12c5d1SDavid du Colombier  * not jumping past nuls in broken utf codes!
116*3e12c5d1SDavid du Colombier  */
117*3e12c5d1SDavid du Colombier char *nextutf(char *p){
118*3e12c5d1SDavid du Colombier 	int u=*p&0xff;
119*3e12c5d1SDavid du Colombier 	if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
120*3e12c5d1SDavid du Colombier 	if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
121*3e12c5d1SDavid du Colombier 	return p+1;
122*3e12c5d1SDavid du Colombier }
123*3e12c5d1SDavid du Colombier /*
124*3e12c5d1SDavid du Colombier  * Convert the utf code at *p to a unicode value
125*3e12c5d1SDavid du Colombier  */
126*3e12c5d1SDavid du Colombier int unicode(char *p){
127*3e12c5d1SDavid du Colombier 	int u=*p&0xff, v;
128*3e12c5d1SDavid du Colombier 	if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
129*3e12c5d1SDavid du Colombier 	if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
130*3e12c5d1SDavid du Colombier 	return u;
131*3e12c5d1SDavid du Colombier }
132*3e12c5d1SDavid du Colombier /*
133*3e12c5d1SDavid du Colombier  * Does the string s match the pattern p
134*3e12c5d1SDavid du Colombier  * . and .. are only matched by patterns starting with .
135*3e12c5d1SDavid du Colombier  * * matches any sequence of characters
136*3e12c5d1SDavid du Colombier  * ? matches any single character
137*3e12c5d1SDavid du Colombier  * [...] matches the enclosed list of characters
138*3e12c5d1SDavid du Colombier  */
139*3e12c5d1SDavid du Colombier int matchfn(char *s, char *p)
140*3e12c5d1SDavid du Colombier {
141*3e12c5d1SDavid du Colombier 	if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
142*3e12c5d1SDavid du Colombier 		return 0;
143*3e12c5d1SDavid du Colombier 	return match(s, p, '/');
144*3e12c5d1SDavid du Colombier }
145*3e12c5d1SDavid du Colombier int match(char *s, char *p, int stop)
146*3e12c5d1SDavid du Colombier {
147*3e12c5d1SDavid du Colombier 	int compl, hit, lo, hi, t, c;
148*3e12c5d1SDavid du Colombier 	for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){
149*3e12c5d1SDavid du Colombier 		if(*p!=GLOB){
150*3e12c5d1SDavid du Colombier 			if(!equtf(p, s)) return 0;
151*3e12c5d1SDavid du Colombier 		}
152*3e12c5d1SDavid du Colombier 		else switch(*++p){
153*3e12c5d1SDavid du Colombier 		case GLOB:
154*3e12c5d1SDavid du Colombier 			if(*s!=GLOB) return 0;
155*3e12c5d1SDavid du Colombier 			break;
156*3e12c5d1SDavid du Colombier 		case '*':
157*3e12c5d1SDavid du Colombier 			for(;;){
158*3e12c5d1SDavid du Colombier 				if(match(s, nextutf(p), stop)) return 1;
159*3e12c5d1SDavid du Colombier 				if(!*s) break;
160*3e12c5d1SDavid du Colombier 				s=nextutf(s);
161*3e12c5d1SDavid du Colombier 			}
162*3e12c5d1SDavid du Colombier 			return 0;
163*3e12c5d1SDavid du Colombier 		case '?':
164*3e12c5d1SDavid du Colombier 			if(*s=='\0') return 0;
165*3e12c5d1SDavid du Colombier 			break;
166*3e12c5d1SDavid du Colombier 		case '[':
167*3e12c5d1SDavid du Colombier 			if(*s=='\0') return 0;
168*3e12c5d1SDavid du Colombier 			c=unicode(s);
169*3e12c5d1SDavid du Colombier 			p++;
170*3e12c5d1SDavid du Colombier 			compl=*p=='~';
171*3e12c5d1SDavid du Colombier 			if(compl) p++;
172*3e12c5d1SDavid du Colombier 			hit=0;
173*3e12c5d1SDavid du Colombier 			while(*p!=']'){
174*3e12c5d1SDavid du Colombier 				if(*p=='\0') return 0;		/* syntax error */
175*3e12c5d1SDavid du Colombier 				lo=unicode(p);
176*3e12c5d1SDavid du Colombier 				p=nextutf(p);
177*3e12c5d1SDavid du Colombier 				if(*p!='-') hi=lo;
178*3e12c5d1SDavid du Colombier 				else{
179*3e12c5d1SDavid du Colombier 					p++;
180*3e12c5d1SDavid du Colombier 					if(*p=='\0') return 0;	/* syntax error */
181*3e12c5d1SDavid du Colombier 					hi=unicode(p);
182*3e12c5d1SDavid du Colombier 					p=nextutf(p);
183*3e12c5d1SDavid du Colombier 					if(hi<lo){ t=lo; lo=hi; hi=t; }
184*3e12c5d1SDavid du Colombier 				}
185*3e12c5d1SDavid du Colombier 				if(lo<=c && c<=hi) hit=1;
186*3e12c5d1SDavid du Colombier 			}
187*3e12c5d1SDavid du Colombier 			if(compl) hit=!hit;
188*3e12c5d1SDavid du Colombier 			if(!hit) return 0;
189*3e12c5d1SDavid du Colombier 			break;
190*3e12c5d1SDavid du Colombier 		}
191*3e12c5d1SDavid du Colombier 	}
192*3e12c5d1SDavid du Colombier 	return *s=='\0';
193*3e12c5d1SDavid du Colombier }
194*3e12c5d1SDavid du Colombier void globlist1(word *gl)
195*3e12c5d1SDavid du Colombier {
196*3e12c5d1SDavid du Colombier 	if(gl){
197*3e12c5d1SDavid du Colombier 		globlist1(gl->next);
198*3e12c5d1SDavid du Colombier 		glob(gl->word);
199*3e12c5d1SDavid du Colombier 	}
200*3e12c5d1SDavid du Colombier }
201*3e12c5d1SDavid du Colombier void globlist(void){
202*3e12c5d1SDavid du Colombier 	word *a;
203*3e12c5d1SDavid du Colombier 	globv=0;
204*3e12c5d1SDavid du Colombier 	globlist1(runq->argv->words);
205*3e12c5d1SDavid du Colombier 	poplist();
206*3e12c5d1SDavid du Colombier 	pushlist();
207*3e12c5d1SDavid du Colombier 	if(globv){
208*3e12c5d1SDavid du Colombier 		for(a=globv;a->next;a=a->next);
209*3e12c5d1SDavid du Colombier 		a->next=runq->argv->words;
210*3e12c5d1SDavid du Colombier 		runq->argv->words=globv;
211*3e12c5d1SDavid du Colombier 	}
212*3e12c5d1SDavid du Colombier }
213