#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 voidglobfree1(Glob *g){ s_free(g->glob); free(g);} static voidglobfree(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;} voidgloblistfree(Globlist *gl){ if(gl == nil) return; globfree(gl->first); free(gl);} voidglobadd(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 voidglobdir(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 voidglobdot(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 voidglobnext(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;}
#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;
}