ref: 4e09200f7e4bf8791c9c720922734e0759206b72
dir: /libxpath/dat.c/
#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) {
n = m;
break;
}
if (m->cond == n) {
n = m;
break;
}
if (m->anode == n) {
n = m;
break;
}
if (m->bnode == 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;
}