174 lines
2.5 KiB
C
174 lines
2.5 KiB
C
|
#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);
|
||
|
}
|