#include "util.h"
xdata_t xdata_new(xdata_type_t type, char *title, char *instructions) {
pool p;
xdata_t xd;
assert((int) type);
p = pool_new();
xd = pmalloco(p, sizeof(struct _xdata_st));
xd->p = p;
xd->type = type;
if(title != NULL) xd->title = pstrdup(xd->p, title);
if(instructions != NULL) xd->instructions = pstrdup(xd->p, instructions);
log_debug(ZONE, "created new xd; title=%s, instructions=%s", title, instructions);
return xd;
}
xdata_field_t xdata_field_new(xdata_t xd, xdata_field_type_t type, char *var, char *label, char *desc, int required) {
xdata_field_t xdf;
assert((int) xd);
assert((int) type);
assert((int) var);
xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
xdf->p = xd->p;
xdf->type = type;
xdf->var = pstrdup(xdf->p, var);
if(label != NULL) xdf->label = pstrdup(xdf->p, label);
if(desc != NULL) xdf->desc = pstrdup(xdf->p, desc);
xdf->required = required;
return xdf;
}
xdata_item_t xdata_item_new(xdata_t xd) {
xdata_item_t xdi;
assert((int) xd);
xdi = pmalloco(xd->p, sizeof(struct _xdata_item_st));
xdi->p = xd->p;
return xdi;
}
void xdata_add_field(xdata_t xd, xdata_field_t xdf) {
assert((int) xd);
assert((int) xdf);
if(xd->fields == NULL)
xd->fields = xd->flast = xdf;
else {
xd->flast->next = xdf;
xd->flast = xdf;
}
}
void xdata_add_rfield(xdata_t xd, xdata_field_t xdf) {
assert((int) xd);
assert((int) xdf);
if(xd->rfields == NULL)
xd->rfields = xd->rflast = xdf;
else {
xd->rflast->next = xdf;
xd->rflast = xdf;
}
}
void xdata_add_field_item(xdata_item_t xdi, xdata_field_t xdf) {
assert((int) xdi);
assert((int) xdf);
if(xdi->fields == NULL)
xdi->fields = xdi->flast = xdf;
else {
xdi->flast->next = xdf;
xdi->flast = xdf;
}
}
void xdata_add_item(xdata_t xd, xdata_item_t xdi) {
assert((int) xd);
assert((int) xdi);
if(xd->items == NULL)
xd->items = xd->ilast = xdi;
else {
xd->ilast->next = xdi;
xd->ilast = xdi;
}
}
void xdata_option_new(xdata_field_t xdf, char *value, int lvalue, char *label, int llabel) {
xdata_option_t xdo;
assert((int) xdf);
assert((int) value);
xdo = pmalloco(xdf->p, sizeof(struct _xdata_option_st));
xdo->p = xdf->p;
if(lvalue <= 0) lvalue = strlen(value);
xdo->value = pstrdupx(xdo->p, value, lvalue);
if(label != NULL) {
if(llabel <= 0) llabel = strlen(label);
xdo->label = pstrdupx(xdo->p, label, llabel);
}
xdf->olast->next = xdo;
xdf->olast = xdo;
if(xdf->options == NULL) xdf->options = xdo;
}
void xdata_add_value(xdata_field_t xdf, char *value, int vlen) {
int first = 0;
assert((int) xdf);
assert((int) value);
if(vlen <= 0) vlen = strlen(value);
if(xdf->values == NULL)
first = 1;
xdf->values = (char **) realloc(xdf->values, sizeof(char *) * (xdf->nvalues + 1));
xdf->values[xdf->nvalues] = pstrdupx(xdf->p, value, vlen);
xdf->nvalues++;
if(first)
pool_cleanup(xdf->p, free, xdf->values);
}
static xdata_field_t _xdata_field_parse(xdata_t xd, nad_t nad, int root) {
xdata_field_t xdf;
int attr, elem, eval;
xdf = pmalloco(xd->p, sizeof(struct _xdata_field_st));
xdf->p = xd->p;
attr = nad_find_attr(nad, root, -1, "var", NULL);
if(attr >= 0)
xdf->var = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
attr = nad_find_attr(nad, root, -1, "label", NULL);
if(attr >= 0)
xdf->label = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
attr = nad_find_attr(nad, root, -1, "desc", NULL);
if(attr >= 0)
xdf->desc = pstrdupx(xdf->p, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
if(nad_find_elem(nad, root, NAD_ENS(nad, root), "required", 1) >= 0)
xdf->required = 1;
attr = nad_find_attr(nad, root, -1, "type", NULL);
if(attr >= 0) {
if(NAD_AVAL_L(nad, attr) == 7 && strncmp("boolean", NAD_AVAL(nad, attr), 7) == 0)
xdf->type = xd_field_BOOLEAN;
else if(NAD_AVAL_L(nad, attr) == 5 && strncmp("fixed", NAD_AVAL(nad, attr), 5) == 0)
xdf->type = xd_field_FIXED;
else if(NAD_AVAL_L(nad, attr) == 6 && strncmp("hidden", NAD_AVAL(nad, attr), 6) == 0)
xdf->type = xd_field_HIDDEN;
else if(NAD_AVAL_L(nad, attr) == 9 && strncmp("jid-multi", NAD_AVAL(nad, attr), 9) == 0)
xdf->type = xd_field_JID_MULTI;
else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("jid-single", NAD_AVAL(nad, attr), 10) == 0)
xdf->type = xd_field_JID_SINGLE;
else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("list-multi", NAD_AVAL(nad, attr), 10) == 0)
xdf->type = xd_field_LIST_MULTI;
else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("list-single", NAD_AVAL(nad, attr), 11) == 0)
xdf->type = xd_field_LIST_SINGLE;
else if(NAD_AVAL_L(nad, attr) == 10 && strncmp("text-multi", NAD_AVAL(nad, attr), 10) == 0)
xdf->type = xd_field_TEXT_MULTI;
else if(NAD_AVAL_L(nad, attr) == 12 && strncmp("text-private", NAD_AVAL(nad, attr), 12) == 0)
xdf->type = xd_field_TEXT_PRIVATE;
else if(NAD_AVAL_L(nad, attr) == 11 && strncmp("text-single", NAD_AVAL(nad, attr), 11) == 0)
xdf->type = xd_field_TEXT_SINGLE;
else {
log_debug(ZONE, "unknown field type '%.*s'", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
return NULL;
}
}
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "value", 1);
while(elem >= 0) {
if(NAD_CDATA_L(nad, elem) <= 0) {
log_debug(ZONE, "value element requires cdata");
return NULL;
}
xdata_add_value(xdf, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 0);
}
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "options", 1);
while(elem >= 0) {
eval = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "value", 1);
if(eval < 0) {
log_debug(ZONE, "option requires value subelement");
return NULL;
}
if(NAD_CDATA_L(nad, eval) <= 0) {
log_debug(ZONE, "value element requires cdata");
return NULL;
}
attr = nad_find_attr(nad, elem, -1, "label", NULL);
if(attr < 0)
xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NAD_AVAL(nad, eval), NAD_AVAL_L(nad, eval));
else
xdata_option_new(xdf, NAD_CDATA(nad, eval), NAD_CDATA_L(nad, eval), NULL, 0);
elem = nad_find_elem(nad, elem, NAD_ENS(nad, elem), "options", 0);
}
return xdf;
}
xdata_t xdata_parse(nad_t nad, int root) {
xdata_t xd;
int atype, elem, field;
xdata_field_t xdf;
assert((int) nad);
assert((int) (root >= 0));
log_debug(ZONE, "building xd from nad");
if(root >= nad->ecur || NAD_NURI_L(nad, NAD_ENS(nad, root)) != strlen(uri_XDATA) || strncmp(uri_XDATA, NAD_NURI(nad, NAD_ENS(nad, root)), strlen(uri_XDATA) != 0) || NAD_ENAME_L(nad, root) != 1 || (NAD_ENAME(nad, root))[0] != 'x') {
log_debug(ZONE, "elem %d does not exist, or is not {x:data}x", root);
return NULL;
}
atype = nad_find_attr(nad, root, -1, "type", NULL);
if(atype < 0) {
log_debug(ZONE, "no type attribute");
return NULL;
}
if(NAD_AVAL_L(nad, atype) == 4 && strncmp("form", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
xd = xdata_new(xd_type_FORM, NULL, NULL);
else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("result", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
xd = xdata_new(xd_type_RESULT, NULL, NULL);
else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("submit", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
xd = xdata_new(xd_type_SUBMIT, NULL, NULL);
else if(NAD_AVAL_L(nad, atype) == 6 && strncmp("cancel", NAD_AVAL(nad, atype), NAD_AVAL_L(nad, atype)) == 0)
xd = xdata_new(xd_type_CANCEL, NULL, NULL);
else {
log_debug(ZONE, "unknown xd type %.*s", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype));
return NULL;
}
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "title", 1);
if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
log_debug(ZONE, "no cdata on x/title element");
pool_free(xd->p);
return NULL;
}
xd->title = pmalloco(xd->p, sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
strncpy(xd->title, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "instructions", 1);
if(elem < 0 || NAD_CDATA_L(nad, elem) <= 0) {
log_debug(ZONE, "no cdata on x/instructions element");
pool_free(xd->p);
return NULL;
}
xd->instructions = pstrdupx(xd->p, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem));
switch(xd->type) {
case xd_type_FORM:
case xd_type_SUBMIT:
field = nad_find_elem(nad, root, NAD_ENS(nad, root), "field", 1);
while(field >= 0) {
xdf = _xdata_field_parse(xd, nad, field);
if(xdf == NULL) {
log_debug(ZONE, "field parse failed");
pool_free(xd->p);
return NULL;
}
xdata_add_field(xd, xdf);
field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
}
break;
case xd_type_RESULT:
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "reported", 1);
if(elem >= 0) {
field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
while(field >= 0) {
xdf = _xdata_field_parse(xd, nad, field);
if(xdf == NULL) {
log_debug(ZONE, "field parse failed");
pool_free(xd->p);
return NULL;
}
xdata_add_field(xd, xdf);
field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
}
}
elem = nad_find_elem(nad, root, NAD_ENS(nad, root), "item", 1);
if(elem >= 0) {
field = nad_find_elem(nad, elem, NAD_ENS(nad, root), "field", 1);
while(field >= 0) {
xdf = _xdata_field_parse(xd, nad, field);
if(xdf == NULL) {
log_debug(ZONE, "field parse failed");
pool_free(xd->p);
return NULL;
}
xdata_add_field(xd, xdf);
field = nad_find_elem(nad, field, NAD_ENS(nad, root), "field", 0);
}
}
break;
case xd_type_CANCEL:
break;
case xd_type_NONE:
break;
}
return xd;
}