Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}