#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