From ce05175372a9ddca1a225db0765ace1127a39293 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 12 Nov 2021 09:22:01 -0800 Subject: chore: simplified organizational structure --- src/cmd/rc/var.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 src/cmd/rc/var.c (limited to 'src/cmd/rc/var.c') diff --git a/src/cmd/rc/var.c b/src/cmd/rc/var.c new file mode 100644 index 0000000..3e9635f --- /dev/null +++ b/src/cmd/rc/var.c @@ -0,0 +1,336 @@ +#include "rc.h" +#include "parse.h" + +// TODO: string interning + +// ----------------------------------------------------------------------- +// globals + +struct Keyword +{ + char *name; + int type; +}; + +static Var *globals[512]; +static struct Keyword keywords[100]; // sparse map means less hits + +// ----------------------------------------------------------------------- +// 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(shell.err); + } + + 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(runner){ + for(v = runner->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= runner->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=runner->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(shell.err); + bigpath(v); +} + +#define KEYWORDS \ + KEYWORD("for", Tfor) \ + KEYWORD("in", Tin) \ + KEYWORD("while", Twhile) \ + KEYWORD("if", Tif) \ + KEYWORD("else", Telse) \ + KEYWORD("switch", Tswitch) \ + KEYWORD("case", Tcase) \ + KEYWORD("!", Tbang) \ + KEYWORD("@", Tsubshell) \ + KEYWORD("func", Tfunc) + +void +initkeywords(void) +{ + int i, s, j, h; +#define KEYWORD(a, b) a, + static char *name[] = { KEYWORDS }; +#undef KEYWORD +#define KEYWORD(a, b) b, + static int type[] = { KEYWORDS }; +#undef KEYWORD + + for(i = 0; i < arrlen(type); i++){ + h = hash(name[i], arrlen(keywords)); + for(s=0; s < arrlen(keywords); s++){ + j = (h + s) % arrlen(keywords); + if(!keywords[j].type || strcmp(keywords[j].name, name[i]) == 0){ + keywords[j].name = name[i]; + keywords[j].type = type[i]; + goto nextkeyword; + } + } + nextkeyword:; + } +} + +int +iskeyword(char *word) +{ + int i, s, h; + + h = hash(word, arrlen(keywords)); + for(s = 0; s < arrlen(keywords); s++){ + i = (h + s) % arrlen(keywords); + if(!keywords[i].type) + return 0; + if(strcmp(keywords[i].name, word) == 0) + return keywords[i].type; + } + return 0; +} + +#undef KEYWORDS -- cgit v1.2.1