shithub: xml-9atom

ref: f1e559d47916b74f473153a0a04df6956ca4052b
dir: /libxpath/dat.c/

View raw version
#include <u.h>
#include <libc.h>
#include <xml.h>
#include <xpath.h>
#include "dat.h"

char *typestrings[] = {
	"root",
	"string",
	"number",
	"child",
	"attribute",
	"function",
	"descendant-or-self",
	"AND",
	"OR",
	"INDEX",
	"EQ",
	"NEQ",
	"LT",
	"GT",
	"LE",
	"GE",
	nil
};

char*
type2str(int type)
{
	if (type >= NEND)
		return nil;
	if (type < 0)
		return nil;
	return typestrings[type];
}

Name *firstname;
Name *lastname;
Node *firstnode;
Node *lastnode;
Func *firstfunc;
Func *lastfunc;
Mbuf *firstmbuf;
Mbuf *lastmbuf;

Node *rootchain;

Name*
findname(char *n)
{
	Name *nm;
	
	if (!n)
		return nil;
	
	for (nm = firstname; nm; nm = nm->next)
		if (nm->name && strcmp(nm->name, n) == 0)
			return nm;
	return nil;
}

Name*
addname(char *n)
{
	Name *nm;
	int quoted, l;
	
	quoted = 0;
	if (*n == '\'') {
		quoted = 1;
		n++;
		l = strlen(n);
		n[l-1] = 0;
	}
	
	if (!firstname) {
		firstname = mallocz(sizeof(Name), 1);
		firstname->name = strdup(n);
		firstname->quoted = quoted;
		lastname = firstname;
		return firstname;
	}
	
	nm = findname(n);
	if (nm)
		return nm;
	
	lastname->next = mallocz(sizeof(Name), 1);
	lastname = lastname->next;
	lastname->name = strdup(n);
	lastname->quoted = quoted;
	return lastname;
}

static Node*
gennode(void)
{
	if (!firstnode) {
		firstnode = mallocz(sizeof(Node), 1);
		lastnode = firstnode;
		return firstnode;
	}
	lastnode->next = mallocz(sizeof(Node), 1);
	lastnode = lastnode->next;
	return lastnode;
}

Node*
addcondcnode(int type, Node *a, Node *b)
{
	Node *n;
	n = gennode();
	n->type = type;
	n->anode = a;
	n->bnode = b;
	return n;
}

Node*
addnode(Name *name, int type, Node *cond)
{
	Node *n;
	n = gennode();
	
	if (name && name->quoted)
		type = Nstring;
	
	n->name = name;
	n->type = type;
	n->cond = cond;
	
	switch (type) {
	case Nfunction:
		n->func = findfunc(name);
		break;
	}
	return n;
}

Node*
addnoden(int number, Node *cond)
{
	Node *n;
	n = gennode();
	
	n->type = Nnumber;
	n->number = number;
	n->cond = cond;
	return n;
}

Node*
chainnode(Node *base, Node *new)
{
	Node *o;
	o = base;
	while (base->chain)
		base = base->chain;
	base->chain = new;
	return o;
}

Func*
findfunc(Name *name)
{
	Func *f;
	for (f = firstfunc; f; f = f->next)
		if (f->name == name)
			return f;
	return nil;
}

Func*
addfunc(Name *name, void (*f)(XpResult*, Elem*))
{
	Func *func;
	
	func = findfunc(name);
	if (func)
		sysfatal("double registering function: %s", name->name);
	
	if (!firstfunc) {
		firstfunc = mallocz(sizeof(Func), 1);
		firstfunc->name = name;
		firstfunc->f = f;
		lastfunc = firstfunc;
		return firstfunc;
	}
	lastfunc->next = mallocz(sizeof(Func), 1);
	lastfunc = lastfunc->next;
	lastfunc->name = name;
	lastfunc->f = f;
	return lastfunc;
}

static void
debugindent(int level)
{
	while (level--)
		fprint(2, "\t");
}

static void
debugprintceq(Node *c, int level)
{
	debugindent(level);
	switch (c->type) {
	case Neq:
		fprint(2, "    EQ\n");
		break;
	case Nneq:
		fprint(2, "    NEQ\n");
		break;
	case Nlt:
		fprint(2, "    LT\n");
		break;
	case Ngt:
		fprint(2, "    GT\n");
		break;
	case Nle:
		fprint(2, "    LE\n");
		break;
	case Nge:
		fprint(2, "    GE\n");
		break;
	}
	if (c->anode && c->bnode) {
		debugindent(level);
		fprint(2, "    A: nodes\n");
		debugprintnodes(c->anode, level+1);
		debugindent(level);
		fprint(2, "    B: nodes\n");
		debugprintnodes(c->bnode, level+1);
		return;
	}
}

static void
debugprintcond(Node *c, int level)
{
	if (!c)
		return;
	
	debugindent(level);
	fprint(2, "  Cond:\n");
	
	switch (c->type) {
	case Nand:
		debugprintcond(c->anode, level+1);
		debugindent(level);
		fprint(2, "    AND\n");
		debugprintcond(c->bnode, level+1);
		break;
	case Nor:
		debugprintcond(c->anode, level+1);
		debugindent(level);
		fprint(2, "    OR\n");
		debugprintcond(c->bnode, level+1);
		break;
	case Nindex:
		debugindent(level);
		fprint(2, "    Index: %d\n", c->number);
		break;
	case Nattribute:
		debugindent(level);
		fprint(2, "    Attr: %s == %s\n",
			c->anode->name->name,
			c->bnode && c->bnode->name ? c->bnode->name->name : nil);
		break;
	case Neq:
	case Nneq:
	case Nlt:
	case Ngt:
	case Nle:
	case Nge:
		debugprintceq(c, level);
		break;
	}
}

void
debugprintfunc(Func *f, int level)
{
	if (!f)
		return;
	
	debugindent(level);
	fprint(2, "    Func: %s %p\n", f->name->name, f->f);
}

void
debugprintnodes(Node *node, int level)
{
	Node *n;
	
	for (n = node ? node : rootchain; n; n = n->chain) {
		debugindent(level);
		fprint(2, "Node: %p\n", n);
		debugindent(level);
		fprint(2, "  type: %s\n", type2str(n->type));
		if (n->type >= Nand) {
			debugprintcond(n, level);
			continue;
		}
		switch (n->type) {
		case Nnumber:
			debugindent(level);
			fprint(2, "  number: %d\n", n->number);
			break;
		default:
			debugindent(level);
			fprint(2, "  name: %s\n", n->name ? n->name->name : "<root>");
			break;
		}
		debugprintcond(n->cond, level);
		debugprintfunc(n->func, level);
	}
}

static void
reset(void)
{
	Node *n, *on;
	Name *nm, *onm;
	Func *f, *of;
	Mbuf *m, *om;
	
	for (nm = firstname; nm;) {
		onm = nm->next;
		free(nm->name);
		free(nm);
		nm = onm;
	}
	firstname = lastname = nil;
	
	for (n = firstnode; n;) {
		on = n->next;
		free(n);
		n = on;
	}
	firstnode = lastnode = nil;
	
	for (f = firstfunc; f;) {
		of = f->next;
		free(f);
		f = of;
	}
	firstfunc = lastfunc = nil;
	
	for (m = firstmbuf; m;) {
		om = m->next;
		free(m->ptr);
		free(m);
		m = om;
	}
	firstmbuf = lastmbuf = nil;
	
	initfuncs();
}

void
regmbuf(void *ptr)
{
	if (!firstmbuf) {
		firstmbuf = mallocz(sizeof(Mbuf), 1);
		firstmbuf->ptr = ptr;
		lastmbuf = firstmbuf;
		return;
	}
	lastmbuf->next = mallocz(sizeof(Mbuf), 1);
	lastmbuf = lastmbuf->next;
	lastmbuf->ptr = ptr;
}

void setinputpath(char*);
int yyparse(void);

Node*
findroot(void)
{
	Node *n, *m;
	
	/* find unlinked node */
	for (n = firstnode; n;) {
		for (m = firstnode; m; m = m->next) {
			if (n == m) {
				continue;
			}
			if (m->chain == n) {
				fprint(2, "%p chained %p\n", m, n);
				n = m;
				break;
			}
			if (m->cond == n) {
				fprint(2, "%p cond %p\n", m, n);
				n = m;
				break;
			}
			if (m->anode == n) {
				fprint(2, "%p anode %p\n", m, n);
				n = m;
				break;
			}
			if (m->bnode == n) {
				fprint(2, "%p bnode %p\n", m, n);
				n = m;
				break;
			}
		}
		if (!m) {
			/* if no node links to n, n is root */
			return n;
		}
		/* if m is valid, n == m. Proceed with new n. */
	}
	return nil;
}

Node*
parsexpath(char *s)
{
	reset();
	setinputpath(s);
	if (!yyparse()) { /* if successful */
		rootchain = findroot();
		return rootchain;
	}
	werrstr("syntax error");
	return nil;
}

void
buildsinglestring(XpResult *r, char *s)
{
	r->type = Xstring;
	r->num = r->size = 1;
	r->strings = malloc(sizeof(char*));
	r->strings[0] = s;
}

void
buildsingleelem(XpResult *r, Elem *e)
{
	r->type = Xelem;
	r->num = r->size = 1;
	r->elems = malloc(sizeof(Elem*));
	r->elems[0] = e;
}

void
buildsinglenum(XpResult *r, int n)
{
	r->type = Xnum;
	r->num = r->size = 1;
	r->numbers = malloc(sizeof(int));
	r->numbers[0] = n;
}