| #include "rc.h" |
| #include "exec.h" |
| #include "fns.h" |
| |
| int |
| hash(char *s, int n) |
| { |
| int h = 0, i = 1; |
| while(*s) h+=*s++*i++; |
| h%=n; |
| return h<0?h+n:h; |
| } |
| #define NKW 30 |
| struct kw{ |
| char *name; |
| int type; |
| struct kw *next; |
| }*kw[NKW]; |
| |
| void |
| kenter(int type, char *name) |
| { |
| int h = hash(name, NKW); |
| struct kw *p = new(struct kw); |
| p->type = type; |
| p->name = name; |
| p->next = kw[h]; |
| kw[h] = p; |
| } |
| |
| void |
| kinit(void) |
| { |
| kenter(FOR, "for"); |
| kenter(IN, "in"); |
| kenter(WHILE, "while"); |
| kenter(IF, "if"); |
| kenter(NOT, "not"); |
| kenter(TWIDDLE, "~"); |
| kenter(BANG, "!"); |
| kenter(SUBSHELL, "@"); |
| kenter(SWITCH, "switch"); |
| kenter(FN, "fn"); |
| } |
| |
| tree* |
| klook(char *name) |
| { |
| struct kw *p; |
| tree *t = token(name, WORD); |
| for(p = kw[hash(name, NKW)];p;p = p->next) |
| if(strcmp(p->name, name)==0){ |
| t->type = p->type; |
| t->iskw = 1; |
| break; |
| } |
| return t; |
| } |
| |
| var* |
| gvlook(char *name) |
| { |
| int h = hash(name, NVAR); |
| var *v; |
| for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v; |
| return gvar[h] = newvar(strdup(name), gvar[h]); |
| } |
| |
| var* |
| vlook(char *name) |
| { |
| var *v; |
| if(runq) |
| for(v = runq->local;v;v = v->next) |
| if(strcmp(v->name, name)==0) return v; |
| return gvlook(name); |
| } |
| |
| void |
| _setvar(char *name, word *val, int callfn) |
| { |
| struct var *v = vlook(name); |
| freewords(v->val); |
| v->val=val; |
| v->changed=1; |
| if(callfn && v->changefn) |
| v->changefn(v); |
| } |
| |
| void |
| setvar(char *name, word *val) |
| { |
| _setvar(name, val, 1); |
| } |
| |
| 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->word; |
| 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 = newword(p[0] ? p : ".", nil); |
| l = &(*l)->next; |
| if(q){ |
| *q = ':'; |
| p = q+1; |
| }else |
| p = nil; |
| } |
| _setvar("path", w, 0); |
| } |
| |
| char* |
| list2strcolon(word *words) |
| { |
| char *value, *s, *t; |
| int len = 0; |
| word *ap; |
| for(ap = words;ap;ap = ap->next) |
| len+=1+strlen(ap->word); |
| value = emalloc(len+1); |
| s = value; |
| for(ap = words;ap;ap = ap->next){ |
| for(t = ap->word;*t;) *s++=*t++; |
| *s++=':'; |
| } |
| if(s==value) |
| *s='\0'; |
| else s[-1]='\0'; |
| return value; |
| } |
| void |
| littlepath(var *v) |
| { |
| /* convert $path to $PATH */ |
| char *p; |
| word *w; |
| |
| p = list2strcolon(v->val); |
| w = new(word); |
| w->word = p; |
| w->next = nil; |
| _setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */ |
| } |
| |
| void |
| pathinit(void) |
| { |
| var *v; |
| |
| v = gvlook("path"); |
| v->changefn = littlepath; |
| v = gvlook("PATH"); |
| v->changefn = bigpath; |
| bigpath(v); |
| } |