]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/glob.c
Libflac: Tell it that we have stdint.h so it finds SIZE_MAX
[plan9front.git] / sys / src / cmd / rc / glob.c
1 #include "rc.h"
2 #include "exec.h"
3 #include "fns.h"
4
5 /*
6  * delete all the GLOB marks from s, in place
7  */
8
9 char*
10 deglob(char *s)
11 {
12         char *b = s;
13         char *t = s;
14         do{
15                 if(*t==GLOB)
16                         t++;
17                 *s++=*t;
18         }while(*t++);
19         return b;
20 }
21
22 static int
23 globcmp(void *s, void *t)
24 {
25         return strcmp(*(char**)s, *(char**)t);
26 }
27
28 static void
29 globsort(word *left, word *right)
30 {
31         char **list;
32         word *a;
33         int n = 0;
34         for(a = left;a!=right;a = a->next) n++;
35         list = (char **)emalloc(n*sizeof(char *));
36         for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
37         qsort((void *)list, n, sizeof(void *), globcmp);
38         for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
39         free(list);
40 }
41
42 /*
43  * Does the string s match the pattern p
44  * . and .. are only matched by patterns starting with .
45  * * matches any sequence of characters
46  * ? matches any single character
47  * [...] matches the enclosed list of characters
48  */
49
50 static int
51 matchfn(char *s, char *p)
52 {
53         if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
54                 return 0;
55         return match(s, p, '/');
56 }
57
58 static word*
59 globdir(word *list, char *p, char *name, char *namep)
60 {
61         char *t, *newp;
62         int f;
63         /* scan the pattern looking for a component with a metacharacter in it */
64         if(*p=='\0')
65                 return newword(name, list);
66         t = namep;
67         newp = p;
68         while(*newp){
69                 if(*newp==GLOB)
70                         break;
71                 *t=*newp++;
72                 if(*t++=='/'){
73                         namep = t;
74                         p = newp;
75                 }
76         }
77         /* If we ran out of pattern, append the name if accessible */
78         if(*newp=='\0'){
79                 *t='\0';
80                 if(access(name, 0)==0)
81                         list = newword(name, list);
82                 return list;
83         }
84         /* read the directory and recur for any entry that matches */
85         *namep='\0';
86         if((f = Opendir(name[0]?name:".")) >= 0){
87                 while(*newp!='/' && *newp!='\0') newp++;
88                 while(Readdir(f, namep, *newp=='/')){
89                         if(matchfn(namep, p)){
90                                 for(t = namep;*t;t++);
91                                 list = globdir(list, newp, name, t);
92                         }
93                 }
94                 Closedir(f);
95         }
96         return list;
97 }
98
99 /*
100  * Subsitute a word with its glob in place.
101  */
102
103 static void
104 globword(word *w)
105 {
106         word *left, *right;
107         char *name;
108
109         if(w->glob == 0)
110                 return;
111         name = emalloc(w->glob);
112         memset(name, 0, w->glob);
113         right = w->next;
114         left = globdir(right, w->word, name, name);
115         free(name);
116         if(left == right) {
117                 deglob(w->word);
118                 w->glob = 0;
119         } else {
120                 free(w->word);
121                 globsort(left, right);
122                 *w = *left;
123                 free(left);
124         }
125 }
126
127 word*
128 globlist(word *l)
129 {
130         word *p, *q;
131
132         for(p=l;p;p=q){
133                 q = p->next;
134                 globword(p);
135         }
136         return l;
137 }
138
139 /*
140  * Return a pointer to the next utf code in the string,
141  * not jumping past nuls in broken utf codes!
142  */
143
144 static char*
145 nextutf(char *p)
146 {
147         Rune dummy;
148
149         return p + chartorune(&dummy, p);
150 }
151
152 /*
153  * Convert the utf code at *p to a unicode value
154  */
155
156 static int
157 unicode(char *p)
158 {
159         Rune r;
160
161         chartorune(&r, p);
162         return r;
163 }
164
165 /*
166  * Do p and q point at equal utf codes
167  */
168
169 static int
170 equtf(char *p, char *q)
171 {
172         if(*p!=*q)
173                 return 0;
174         return unicode(p) == unicode(q);
175 }
176
177 int
178 match(char *s, char *p, int stop)
179 {
180         int compl, hit, lo, hi, t, c;
181
182         for(; *p!=stop && *p!='\0'; s = nextutf(s), p = nextutf(p)){
183                 if(*p!=GLOB){
184                         if(!equtf(p, s)) return 0;
185                 }
186                 else switch(*++p){
187                 case GLOB:
188                         if(*s!=GLOB)
189                                 return 0;
190                         break;
191                 case '*':
192                         for(;;){
193                                 if(match(s, nextutf(p), stop)) return 1;
194                                 if(!*s)
195                                         break;
196                                 s = nextutf(s);
197                         }
198                         return 0;
199                 case '?':
200                         if(*s=='\0')
201                                 return 0;
202                         break;
203                 case '[':
204                         if(*s=='\0')
205                                 return 0;
206                         c = unicode(s);
207                         p++;
208                         compl=*p=='~';
209                         if(compl)
210                                 p++;
211                         hit = 0;
212                         while(*p!=']'){
213                                 if(*p=='\0')
214                                         return 0;               /* syntax error */
215                                 lo = unicode(p);
216                                 p = nextutf(p);
217                                 if(*p!='-')
218                                         hi = lo;
219                                 else{
220                                         p++;
221                                         if(*p=='\0')
222                                                 return 0;       /* syntax error */
223                                         hi = unicode(p);
224                                         p = nextutf(p);
225                                         if(hi<lo){ t = lo; lo = hi; hi = t; }
226                                 }
227                                 if(lo<=c && c<=hi)
228                                         hit = 1;
229                         }
230                         if(compl)
231                                 hit=!hit;
232                         if(!hit)
233                                 return 0;
234                         break;
235                 }
236         }
237         return *s=='\0';
238 }