summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ip/glob.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ip/glob.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ip/glob.c')
-rwxr-xr-xsys/src/cmd/ip/glob.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/sys/src/cmd/ip/glob.c b/sys/src/cmd/ip/glob.c
new file mode 100755
index 000000000..346a1e480
--- /dev/null
+++ b/sys/src/cmd/ip/glob.c
@@ -0,0 +1,219 @@
+#include <u.h>
+#include <libc.h>
+#include <regexp.h>
+#include <String.h>
+#include "glob.h"
+
+/*
+ * I wrote this glob so that there would be no limit
+ * on element or path size. The one in rc is probably
+ * better, certainly faster. - presotto
+ */
+
+static Glob*
+globnew(void)
+{
+ Glob *g;
+
+ g = mallocz(sizeof(*g), 1);
+ if(g == nil)
+ sysfatal("globnew: %r");
+ return g;
+}
+
+static void
+globfree1(Glob *g)
+{
+ s_free(g->glob);
+ free(g);
+}
+
+static void
+globfree(Glob *g)
+{
+ Glob *next;
+
+ for(; g != nil; g = next){
+ next = g->next;
+ globfree1(g);
+ }
+}
+
+static Globlist*
+globlistnew(char *x)
+{
+ Globlist *gl;
+
+ gl = mallocz(sizeof *gl, 1);
+ if(gl == nil)
+ sysfatal("globlistnew: %r");
+ gl->first = globnew();
+ gl->first->glob = s_copy(x);
+ gl->l = &gl->first->next;
+ return gl;
+}
+
+void
+globlistfree(Globlist *gl)
+{
+ if(gl == nil)
+ return;
+ globfree(gl->first);
+ free(gl);
+}
+
+void
+globadd(Globlist *gl, char *dir, char *file)
+{
+ Glob *g;
+
+ g = globnew();
+ g->glob = s_copy(dir);
+ if(strcmp(dir, "/") != 0 && *dir != 0)
+ s_append(g->glob, "/");
+ s_append(g->glob, file);
+ *(gl->l) = g;
+ gl->l = &(g->next);
+}
+
+static void
+globdir(Globlist *gl, char *dir, Reprog *re)
+{
+ Dir *d;
+ int i, n, fd;
+
+ if(*dir == 0)
+ fd = open(".", OREAD);
+ else
+ fd = open(dir, OREAD);
+ if(fd < 0)
+ return;
+ n = dirreadall(fd, &d);
+ if(n == 0)
+ return;
+ close(fd);
+ for(i = 0; i < n; i++)
+ if(regexec(re, d[i].name, nil, 0))
+ globadd(gl, dir, d[i].name);
+ free(d);
+}
+
+static void
+globdot(Globlist *gl, char *dir)
+{
+ Dir *d;
+
+ if(*dir == 0){
+ globadd(gl, "", ".");
+ return;
+ }
+ d = dirstat(dir);
+ if(d == nil)
+ return;
+ if(d->qid.type & QTDIR)
+ globadd(gl, dir, ".");
+ free(d);
+}
+
+static void
+globnext(Globlist *gl, char *pattern)
+{
+ String *np;
+ Glob *g, *inlist;
+ Reprog *re;
+ int c;
+
+ /* nothing left */
+ if(*pattern == 0)
+ return;
+
+ inlist = gl->first;
+ gl->first = nil;
+ gl->l = &gl->first;
+
+ /* pick off next pattern and turn into a reg exp */
+ np = s_new();
+ s_putc(np, '^');
+ for(; c = *pattern; pattern++){
+ if(c == '/'){
+ pattern++;
+ break;
+ }
+ switch(c){
+ case '|':
+ case '+':
+ case '.':
+ case '^':
+ case '$':
+ case '(':
+ case ')':
+ s_putc(np, '\\');
+ s_putc(np, c);
+ break;
+ case '?':
+ s_putc(np, '.');
+ break;
+ case '*':
+ s_putc(np, '.');
+ s_putc(np, '*');
+ break;
+ default:
+ s_putc(np, c);
+ break;
+ }
+ }
+ s_putc(np, '$');
+ s_terminate(np);
+ if(strcmp(s_to_c(np), "^\\.$") == 0){
+ /* anything that's a directory works */
+ for(g = inlist; g != nil; g = g->next)
+ globdot(gl, s_to_c(g->glob));
+ } else {
+ re = regcomp(s_to_c(np));
+
+ /* run input list as directories */
+ for(g = inlist; g != nil; g = g->next)
+ globdir(gl, s_to_c(g->glob), re);
+ free(re);
+ }
+ s_free(np);
+ globfree(inlist);
+
+ if(gl->first != nil)
+ globnext(gl, pattern);
+}
+
+char *
+globiter(Globlist *gl)
+{
+ Glob *g;
+ char *s;
+
+ if(gl->first == nil)
+ return nil;
+ g = gl->first;
+ gl->first = g->next;
+ if(gl->first == nil)
+ gl->l = &gl->first;
+ s = strdup(s_to_c(g->glob));
+ if(s == nil)
+ sysfatal("globiter: %r");
+ globfree1(g);
+ return s;
+}
+
+Globlist*
+glob(char *pattern)
+{
+ Globlist *gl;
+
+ if(pattern == nil || *pattern == 0)
+ return nil;
+ if(*pattern == '/'){
+ pattern++;
+ gl = globlistnew("/");
+ } else
+ gl = globlistnew("");
+ globnext(gl, pattern);
+ return gl;
+}