#include <u.h>
#include <libc.h>
#include <auth.h>

int
_attrfmt(Fmt *fmt)
{
	char *b, buf[1024], *ebuf;
	Attr *a;

	ebuf = buf+sizeof buf;
	b = buf;
	strcpy(buf, " ");
	for(a=va_arg(fmt->args, Attr*); a; a=a->next){
		if(a->name == nil)
			continue;
		switch(a->type){
		case AttrQuery:
			b = seprint(b, ebuf, " %q?", a->name);
			break;
		case AttrNameval:
			b = seprint(b, ebuf, " %q=%q", a->name, a->val);
			break;
		case AttrDefault:
			b = seprint(b, ebuf, " %q:=%q", a->name, a->val);
			break;
		}
	}
	return fmtstrcpy(fmt, buf+1);
}

Attr*
_copyattr(Attr *a)
{
	Attr **la, *na;

	na = nil;
	la = &na;
	for(; a; a=a->next){
		*la = _mkattr(a->type, a->name, a->val, nil);
		setmalloctag(*la, getcallerpc(&a));
		la = &(*la)->next;
	}
	*la = nil;
	return na;
}

Attr*
_delattr(Attr *a, char *name)
{
	Attr *fa;
	Attr **la;

	for(la=&a; *la; ){
		if(strcmp((*la)->name, name) == 0){
			fa = *la;
			*la = (*la)->next;
			fa->next = nil;
			_freeattr(fa);
		}else
			la=&(*la)->next;
	}
	return a;
}

Attr*
_findattr(Attr *a, char *n)
{
	for(; a; a=a->next)
		if(strcmp(a->name, n) == 0 && a->type != AttrQuery)
			return a;
	return nil;
}

void
_freeattr(Attr *a)
{
	Attr *anext;

	for(; a; a=anext){
		anext = a->next;
		free(a->name);
		free(a->val);
		a->name = (void*)~0;
		a->val = (void*)~0;
		a->next = (void*)~0;
		free(a);
	}
}

Attr*
_mkattr(int type, char *name, char *val, Attr *next)
{
	Attr *a;

	a = malloc(sizeof(*a));
	if(a==nil)
		sysfatal("_mkattr malloc: %r");
	a->type = type;
	a->name = strdup(name);
	a->val = strdup(val);
	if(a->name==nil || a->val==nil)
		sysfatal("_mkattr malloc: %r");
	a->next = next;
	setmalloctag(a, getcallerpc(&type));
	return a;
}

static Attr*
cleanattr(Attr *a)
{
	Attr *fa;
	Attr **la;

	for(la=&a; *la; ){
		if((*la)->type==AttrQuery && _findattr(a, (*la)->name)){
			fa = *la;
			*la = (*la)->next;
			fa->next = nil;
			_freeattr(fa);
		}else
			la=&(*la)->next;
	}
	return a;
}

Attr*
_parseattr(char *s)
{
	char *p, *t, *tok[256];
	int i, ntok, type;
	Attr *a;

	if(s == nil)
		return nil;

	s = strdup(s);
	if(s == nil)
		sysfatal("_parseattr strdup: %r");

	ntok = tokenize(s, tok, nelem(tok));
	a = nil;
	for(i=ntok-1; i>=0; i--){
		t = tok[i];
		if(p = strchr(t, '=')){
			*p++ = '\0';
		/*	if(p-2 >= t && p[-2] == ':'){ */
		/*		p[-2] = '\0'; */
		/*		type = AttrDefault; */
		/*	}else */
				type = AttrNameval;
			a = _mkattr(type, t, p, a);
			setmalloctag(a, getcallerpc(&s));
		}
		else if(t[strlen(t)-1] == '?'){
			t[strlen(t)-1] = '\0';
			a = _mkattr(AttrQuery, t, "", a);
			setmalloctag(a, getcallerpc(&s));
		}else{
			/* really a syntax error, but better to provide some indication */
			a = _mkattr(AttrNameval, t, "", a);
			setmalloctag(a, getcallerpc(&s));
		}
	}
	free(s);
	return cleanattr(a);
}

char*
_strfindattr(Attr *a, char *n)
{
	a = _findattr(a, n);
	if(a == nil)
		return nil;
	return a->val;
}
