diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/cmd/ip/glob.c | 219 |
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; +} |