123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- #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;
- }
|