#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);
}