From 5baa63ab502c98f6f62368302d92b6b90f9fcd26 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Mon, 15 Nov 2021 18:43:39 -0800 Subject: Feat: globbing Introduced shell globbing --- src/cmd/rc/exec.c | 47 +++++++++++--- src/cmd/rc/glob.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/cmd/rc/rc.h | 7 ++- 3 files changed, 206 insertions(+), 26 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/rc/exec.c b/src/cmd/rc/exec.c index a551d52..62375df 100644 --- a/src/cmd/rc/exec.c +++ b/src/cmd/rc/exec.c @@ -103,8 +103,7 @@ freelist(Word *w) } -static -void +static void pushlist(void) { List *stack = emalloc(sizeof(*stack)); @@ -115,8 +114,7 @@ pushlist(void) runner->args = stack; } -static -void +static void poplist(void) { List *stack = runner->args; @@ -128,6 +126,24 @@ poplist(void) efree(stack); } +static void +globargs(void) +{ + Word *arg; + + globmatch = nil; + globlist(runner->args->word); + poplist(); + pushlist(); + if(globmatch){ + for(arg=globmatch; arg->link; arg = arg->link) + ; + arg->link= runner->args->word; + runner->args->word = globmatch; + } +} + + /* system interop */ static Word* @@ -792,7 +808,7 @@ Xdollar(void) return; } s = runner->args->word->str; - // deglob(s); + deglob(s); n = 0; for(t = s;'0'<=*t && *t<='9';t++) @@ -846,7 +862,7 @@ getindex(Word *array, int len, Word *index, Word *tail) tail = getindex(array, len, index->link, tail); s = index->str; - //deglob(s) + deglob(s); m = 0, n = 0; while('0' <= *s && *s <= '9') @@ -881,7 +897,7 @@ Xindex(void) return; } s = runner->args->word->str; - //deglob(s) + deglob(s); val = var(s)->val; poplist(); @@ -934,6 +950,12 @@ Xjoin(void) efree(s); } +void +Xglob(void) +{ + globargs(); +} + void Xassign(void) { @@ -943,11 +965,11 @@ Xassign(void) Xerror("variable name not singleton!\n"); return; } - //deglob(runq->argv->words->word); + deglob(runner->args->word->str); v = var(runner->args->word->str); poplist(); - //globlist(); + globargs(); freewords(v->val); v->val = runner->args->word; v->new = 1; @@ -991,7 +1013,7 @@ Xlocal(void) Xerror("variable name must be singleton\n"); return; } - //deglob(shell->args->word->str); + deglob(runner->args->word->str); runner->local = makevar(strdup(runner->args->word->str), runner->local); runner->local->val = copywords(runner->args->link->word, nil); @@ -1141,6 +1163,7 @@ Xbasic(void) int pid, status; struct Builtin *b; + globargs(); arg = runner->args->word; if(!arg){ Xerror("empty argument list\n"); @@ -1189,6 +1212,8 @@ Xcount(void) } str = runner->args->word->str; + deglob(str); + arg = var(str)->val; poplist(); @@ -1209,6 +1234,8 @@ Xflat(void) } str = runner->args->word->str; + deglob(str); + arg = var(str)->val; poplist(); diff --git a/src/cmd/rc/glob.c b/src/cmd/rc/glob.c index 9d88b59..eee0318 100644 --- a/src/cmd/rc/glob.c +++ b/src/cmd/rc/glob.c @@ -1,25 +1,16 @@ #include "rc.h" +#include -/* removes glob marks in place */ -void -deglob(char *s) -{ - char *t = s; - do{ - if(*t==GLOB) - t++; - *s++=*t; - }while(*t++); -} +Word *globmatch = nil; +static char *globbuf = nil; int match(char *s, char *p, int stop) { rune rs, rp, lo, hi; - int neg, hit; + int np, ns, neg, hit; - utf8·decode(p, &rp), utf8·decode(s, &rs); - for(; *p && *p != stop; s+=utf8·decode(s,&rs),p+=utf8·decode(p,&rp)){ + for(np=utf8·decode(p, &rp), ns=utf8·decode(s, &rs); *p && *p != stop; s+=ns, p+=np, ns=utf8·decode(s,&rs), np=utf8·decode(p,&rp)){ /* fast path: normal character */ if(*p != GLOB){ if(rp != rs) @@ -34,10 +25,12 @@ match(char *s, char *p, int stop) return 0; break; case '*': + p += utf8·decode(p, &rp); for(;;){ - p += utf8·decode(p, &rp); if(match(s, p, stop)) return 1; + if(!*s) + break; s += utf8·decode(s, &rs); } return 0; @@ -80,3 +73,158 @@ match(char *s, char *p, int stop) return *s == 0; } + +static int +matchpath(char *s, char *p) +{ + if(s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0) && p[0] != '.') + return 0; + return match(s, p, '/'); +} + +/* removes glob marks in place */ +void +deglob(char *s) +{ + char *t = s; + do{ + if(*t==GLOB) + t++; + *s++=*t; + }while(*t++); +} + +#define DIRLEN 256 +static int +globsize(char *p) +{ + ulong is=0, len=DIRLEN+1; + for(;*p;p++){ + if(*p!=GLOB) + len++; + else{ + p++; + if(*p != GLOB) + is++; + len += (*p == '*') ? DIRLEN : 1; + } + } + return is ? len : 0; +} +#undef DIRLEN + +static void +globpath(char *p, char *buf) +{ + int fd; + char *s, *base; + DIR *dir; + struct dirent *sub; + + if(*p == 0){ + globmatch = makeword(globbuf, globmatch); + return; + } + + s=buf, base=p; + while(*base){ + if(*base==GLOB) + break; + *s = *base++; + if(*s++ == '/'){ + buf=s, p=base; + } + } + + /* we ran out of pattern, no glob */ + if(*base == 0){ + *s = 0; + if(os·exists(globbuf, 0)) + globmatch = makeword(globbuf, globmatch); + return; + } + + *buf = 0; + /* read the directory and recurse for any entry that matches */ + /* TODO: replace ugly C interface with something else */ + fd = openat(AT_FDCWD, globbuf[0] ? globbuf : ".", O_RDONLY | O_CLOEXEC | O_DIRECTORY); + if(fd < 0) + return; + if(!(dir = fdopendir(fd))){ + close(fd); + return; + } + + while(*base != '/' && *base != 0) + base++; + + while((sub=readdir(dir))){ + strcpy(buf, sub->d_name); + if(matchpath(buf, p)){ + for(s=buf; *s; s++) + ; + globpath(base, s); + } + } + closedir(dir); +} + +static void +sort(Word *left, Word *right) +{ + int n,f; + Word *arg; + char **arr, *buf[256]; + + for(arg=left,n=0; arg != right; arg=arg->link) + n++; + + if(nlink,n++) + arr[n] = arg->str; + + sort·string(n,arr); + + for(arg=left,n=0; arg!=right; arg=arg->link, n++) + arg->str = arr[n]; + + if(f) + efree(arr); +} + +static void +glob(char *p) +{ + Word *old = globmatch; + int nglob = globsize(p); + if(!nglob) + goto nomatch; + + globbuf = emalloc(nglob); + globbuf[0] = 0; + globpath(p, globbuf); + efree(globbuf); + if(globmatch == old) + goto nomatch; + /* fallthrough */ +match: + sort(globmatch, old); + return; +nomatch: + deglob(p); + globmatch = makeword(p, globmatch); +} + +void +globlist(Word *g) +{ + if(g){ + globlist(g->link); + glob(g->str); + } +} + diff --git a/src/cmd/rc/rc.h b/src/cmd/rc/rc.h index f7533a0..b51b78b 100644 --- a/src/cmd/rc/rc.h +++ b/src/cmd/rc/rc.h @@ -1,3 +1,4 @@ +#pragma once #include #include @@ -265,4 +266,8 @@ void freecode(Code *c); /* glob.c */ #define GLOB ((char)(0x01)) -int match(char *, char *, int); +extern Word *globmatch; + +void deglob(char *); +void globlist(Word *); +int match(char *, char *, int); -- cgit v1.2.1