From bf03074e346b004659196b6c17eee04dbffd3ac2 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Fri, 15 Oct 2021 16:18:02 -0700 Subject: feat(rc): working prototype of input->compile->print loop --- sys/cmd/rc/var.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 sys/cmd/rc/var.c (limited to 'sys/cmd/rc/var.c') diff --git a/sys/cmd/rc/var.c b/sys/cmd/rc/var.c new file mode 100644 index 0000000..f0e5f5b --- /dev/null +++ b/sys/cmd/rc/var.c @@ -0,0 +1,271 @@ +#include "rc.h" + +static Var *globals[512]; + +// ----------------------------------------------------------------------- +// internals + +static +int +hash(char *s, int len) +{ + int h =0, i = 1; + while(*s) + h += *s++*i++; + + h %= len; + return h < 0 ? h+len : h; +} + +static +void +·setvar(char *name, Word *val, int call) +{ + Var *v = var(name); + freeword(v->val); + + v->val = val; + v->new = 1; // this never turns off? + + if(call && v->update) + v->update(v); +} + +static +char* +list2strcolon(Word *words) +{ + char *value, *s, *t; + int len = 0; + Word *ap; + for(ap = words;ap;ap = ap->link) + len+=1+strlen(ap->str); + + value = emalloc(len+1); + + s = value; + for(ap = words; ap; ap = ap->link){ + for(t = ap->str;*t;) *s++=*t++; + *s++=':'; + } + + if(s==value) + *s='\0'; + else + s[-1]='\0'; + + return value; +} + +static +void +littlepath(Var *v) +{ + /* convert $path to $PATH */ + char *p; + Word *w; + + p = list2strcolon(v->val); + w = emalloc(sizeof(*w)); + w->str = p; + w->link = nil; + + ·setvar("PATH", w, 1); +} + +static +void +bigpath(Var *v) +{ + /* convert $PATH to $path */ + char *p, *q; + Word **l, *w; + + if(v->val == nil){ + ·setvar("path", nil, 0); + return; + } + + p = v->val->str; + w = nil; + l = &w; + + /* Doesn't handle escaped colon nonsense. */ + if(p[0] == 0) + p = nil; + + while(p){ + q = strchr(p, ':'); + if(q) + *q = 0; + + *l = makeword(p[0] ? p : ".", nil); + l = &(*l)->link; + + if(q){ + *q = ':'; + p = q+1; + }else + p = nil; + } + ·setvar("path", w, 0); +} + + + +// ----------------------------------------------------------------------- +// exports + +Var* +makevar(char *name, Var *link) +{ + Var *v = emalloc(sizeof(*v)); + + v->name = name; + v->val = 0; + v->new = 0; + v->newfunc = 0; + v->link = link; + v->func = nil; + v->update = nil; + + return v; +} + +void +setvar(char *name, Word *val) +{ + ·setvar(name, val, 1); +} + +Var* +definevar(char *name, Var *link) +{ + Var *v = emalloc(sizeof(*v)); + + v->name = name; + v->val = 0; + v->link = link; + + return v; +} + +Var* +globalvar(char *name) +{ + int h; + Var *v; + + h = hash(name, arrlen(globals)); + + if(strcmp(name,"PATH")==0){ + flush(errio); + } + + for(v = globals[h]; v; v = v->link){ + if(strcmp(v->name, name) == 0){ + return v; + } + } + + return globals[h] = definevar(strdup(name), globals[h]); +} + +Var* +var(char *name) +{ + Var *v; + if(shell){ + for(v = shell->local; v; v=v->link) + if(strcmp(v->name, name) == 0) + return v; + } + return globalvar(name); +} + +static +int +cmpenv(const void *a, const void *b) +{ + return strcmp(*(char**)a, *(char**)b); +} + +char** +mkenv(void) +{ + char **env, **ep, *p, *q; + Var **h, *v; + Word *a; + int nvar=0, nchr=0, sep; + +#define BODY \ + if((v==var(v->name)) && v->val){ \ + nvar++; \ + nchr+=strlen(v->name)+1; \ + for(a=v->val;a;a=a->link) \ + nchr+=strlen(a->str)+1; \ + } + + for(v= shell->local; v; v=v->link){ + BODY + } + for(h=globals; h!=arrend(globals); h++){ + for(v = *h; v; v=v->link){ + BODY + } + } + +#undef BODY + + env=emalloc((nvar+1)*sizeof(*env)+nchr); + ep=env; + p=(char *)&env[nvar+1]; + +#define BODY \ + if((v==var(v->name)) && v->val){ \ + *ep++=p; \ + q=v->name; \ + while(*q) \ + *p++=*q++; \ + sep='='; \ + for(a=v->val;a;a=a->link){ \ + *p++=sep; \ + sep='\1'; \ + q=a->str; \ + while(*q) \ + *p++=*q++; \ + } \ + *p++='\0'; \ + } + + for(v=shell->local; v; v=v->link){ + BODY + } + for(h=globals; h!=arrend(globals); h++){ + for(v = *h; v; v=v->link){ + BODY + } + } +#undef BODY + + *ep=0; + + qsort((char *)env, nvar, sizeof ep[0], cmpenv); + return env; +} + +void +initpath(void) +{ + Var *v; + + v = globalvar("path"); + v->update = littlepath; + + v = globalvar("PATH"); + v->update = bigpath; + + flush(errio); + bigpath(v); +} + -- cgit v1.2.1