]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ip/glob.c
ip/tftpd: remove sunkernel hack
[plan9front.git] / sys / src / cmd / ip / glob.c
1 #include <u.h>
2 #include <libc.h>
3 #include <regexp.h>
4 #include <String.h>
5 #include "glob.h"
6
7 /*
8  *  I wrote this glob so that there would be no limit
9  *  on element or path size.  The one in rc is probably
10  *  better, certainly faster. - presotto
11  */
12
13 static Glob*
14 globnew(void)
15 {
16         Glob *g;
17
18         g = mallocz(sizeof(*g), 1);
19         if(g == nil)
20                 sysfatal("globnew: %r");
21         return g;
22 }
23
24 static void
25 globfree1(Glob *g)
26 {
27         s_free(g->glob);
28         free(g);
29 }
30
31 static void
32 globfree(Glob *g)
33 {
34         Glob *next;
35
36         for(; g != nil; g = next){
37                 next = g->next;
38                 globfree1(g);
39         }
40 }
41
42 static Globlist*
43 globlistnew(char *x)
44 {
45         Globlist *gl;
46
47         gl = mallocz(sizeof *gl, 1);
48         if(gl == nil)
49                 sysfatal("globlistnew: %r");
50         gl->first = globnew();
51         gl->first->glob = s_copy(x);
52         gl->l = &gl->first->next;
53         return gl;
54 }
55
56 void
57 globlistfree(Globlist *gl)
58 {
59         if(gl == nil)
60                 return;
61         globfree(gl->first);
62         free(gl);
63 }
64
65 void
66 globadd(Globlist *gl, char *dir, char *file)
67 {
68         Glob *g;
69
70         g = globnew();
71         g->glob = s_copy(dir);
72         if(strcmp(dir, "/") != 0 && *dir != 0)
73                 s_append(g->glob, "/");
74         s_append(g->glob, file);
75         *(gl->l) = g;
76         gl->l = &(g->next); 
77 }
78
79 static void
80 globdir(Globlist *gl, char *dir, Reprog *re)
81 {
82         Dir *d;
83         int i, n, fd;
84
85         if(*dir == 0)
86                 fd = open(".", OREAD);
87         else
88                 fd = open(dir, OREAD);
89         if(fd < 0)
90                 return;
91         n = dirreadall(fd, &d);
92         if(n == 0)
93                 return;
94         close(fd);
95         for(i = 0; i < n; i++)
96                 if(regexec(re, d[i].name, nil, 0))
97                         globadd(gl, dir, d[i].name);
98         free(d);
99 }
100
101 static void
102 globdot(Globlist *gl, char *dir)
103 {
104         Dir *d;
105
106         if(*dir == 0){
107                 globadd(gl, "", ".");
108                 return;
109         }
110         d = dirstat(dir);
111         if(d == nil)
112                 return;
113         if(d->qid.type & QTDIR)
114                 globadd(gl, dir, ".");
115         free(d);
116 }
117
118 static void
119 globnext(Globlist *gl, char *pattern)
120 {
121         String *np;
122         Glob *g, *inlist;
123         Reprog *re;
124         int c;
125
126         /* nothing left */
127         if(*pattern == 0)
128                 return;
129
130         inlist = gl->first;
131         gl->first = nil;
132         gl->l = &gl->first;
133
134         /* pick off next pattern and turn into a reg exp */
135         np = s_new();
136         s_putc(np, '^');
137         for(; c = *pattern; pattern++){
138                 if(c == '/'){
139                         pattern++;
140                         break;
141                 }
142                 switch(c){
143                 case '|':
144                 case '+':
145                 case '.':
146                 case '^':
147                 case '$':
148                 case '(':
149                 case ')':
150                         s_putc(np, '\\');
151                         s_putc(np, c);
152                         break;
153                 case '?':
154                         s_putc(np, '.');
155                         break;
156                 case '*':
157                         s_putc(np, '.');
158                         s_putc(np, '*');
159                         break;
160                 default:
161                         s_putc(np, c);
162                         break;
163                 }
164         }
165         s_putc(np, '$');
166         s_terminate(np);
167         if(strcmp(s_to_c(np), "^\\.$") == 0){
168                 /* anything that's a directory works */
169                 for(g = inlist; g != nil; g = g->next)
170                         globdot(gl, s_to_c(g->glob));
171         } else {
172                 re = regcomp(s_to_c(np));
173
174                 /* run input list as directories */
175                 for(g = inlist; g != nil; g = g->next)
176                         globdir(gl, s_to_c(g->glob), re);
177                 free(re);
178         }
179         s_free(np);
180         globfree(inlist);
181
182         if(gl->first != nil)
183                 globnext(gl, pattern);
184 }
185
186 char *
187 globiter(Globlist *gl)
188 {
189         Glob *g;
190         char *s;
191
192         if(gl->first == nil)
193                 return nil;
194         g = gl->first;
195         gl->first = g->next;
196         if(gl->first == nil)
197                 gl->l = &gl->first;
198         s = strdup(s_to_c(g->glob));
199         if(s == nil)
200                 sysfatal("globiter: %r");
201         globfree1(g);
202         return s;
203 }
204
205 Globlist*
206 glob(char *pattern)
207 {
208         Globlist *gl;
209
210         if(pattern == nil || *pattern == 0)
211                 return nil;
212         if(*pattern == '/'){
213                 pattern++;
214                 gl = globlistnew("/");
215         } else
216                 gl = globlistnew("");
217         globnext(gl, pattern);
218         return gl;
219 }