/** get a matching ns on this elem, both uri and optional prefix */ int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix) { int check, ns; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || uri == NULL) return -1; /* work backwards through our parents, looking for our namespace on each one. * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */ check = elem; while(check >= 0) { ns = nad->elems[check].ns; while(ns >= 0) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; ns = nad->nss[ns].next; } check = nad->elems[check].parent; } return -1; }
/** wrap an element with another element */ void nad_wrap_elem(nad_t nad, int elem, int ns, const char *name) { int cur; _nad_ptr_check(__func__, nad); if(elem >= nad->ecur) return; NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); /* relocate all the rest of the elems after us */ memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st)); nad->ecur++; /* relink parents on moved elements */ for(cur = elem + 1; cur < nad->ecur; cur++) if(nad->elems[cur].parent > elem + 1) nad->elems[cur].parent++; /* set up req'd parts of new elem */ nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; nad->elems[elem].my_ns = ns; /* raise the bar on all the children */ nad->elems[elem+1].depth++; for(cur = elem + 2; cur < nad->ecur && nad->elems[cur].depth > nad->elems[elem].depth; cur++) nad->elems[cur].depth++; /* hook up the parent */ nad->elems[elem].parent = nad->elems[elem + 1].parent; }
/** locate the next elem at a given depth with an optional matching name */ int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth) { int my_ns; int lname = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur) return -1; /* set up args for searching */ depth = nad->elems[elem].depth + depth; if(name != NULL) lname = strlen(name); /* search */ for(elem++;elem < nad->ecur;elem++) { /* if we hit one with a depth less than ours, then we don't have the * same parent anymore, bail */ if(nad->elems[elem].depth < depth) return -1; if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) && (ns < 0 || ((my_ns = nad->elems[elem].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return elem; } return -1; }
/** get a matching attr on this elem, both name and optional val */ int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val) { int attr, my_ns; int lname, lval = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; attr = nad->elems[elem].attr; lname = strlen(name); if(val != NULL) lval = strlen(val); while(attr >= 0) { /* hefty, match name and if a val, also match that */ if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 && (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) && (ns < 0 || ((my_ns = nad->attrs[attr].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return attr; attr = nad->attrs[attr].next; } return -1; }
nad_t nad_copy(nad_t nad) { nad_t copy; _nad_ptr_check(__func__, nad); if(nad == NULL) return NULL; copy = nad_new(); /* if it's not large enough, make bigger */ NAD_SAFE(copy->elems, nad->elen, copy->elen); NAD_SAFE(copy->attrs, nad->alen, copy->alen); NAD_SAFE(copy->nss, nad->nlen, copy->nlen); NAD_SAFE(copy->cdata, nad->clen, copy->clen); /* copy all data */ memcpy(copy->elems, nad->elems, nad->elen); memcpy(copy->attrs, nad->attrs, nad->alen); memcpy(copy->nss, nad->nss, nad->nlen); memcpy(copy->cdata, nad->cdata, nad->clen); /* sync data */ copy->ecur = nad->ecur; copy->acur = nad->acur; copy->ncur = nad->ncur; copy->ccur = nad->ccur; copy->scope = nad->scope; return copy; }
/** create a new elem on the list */ int nad_append_elem(nad_t nad, int ns, const char *name, int depth) { int elem; _nad_ptr_check(__func__, nad); /* make sure there's mem for us */ NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); elem = nad->ecur; nad->ecur++; nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].depth = depth; nad->elems[elem].my_ns = ns; /* make sure there's mem in the depth array, then track us */ NAD_SAFE(nad->depths, (depth + 1) * sizeof(int), nad->dlen); nad->depths[depth] = elem; /* our parent is the previous guy in the depth array */ if(depth <= 0) nad->elems[elem].parent = -1; else nad->elems[elem].parent = nad->depths[depth - 1]; return elem; }
/** bring a new namespace into scope */ int nad_add_namespace(nad_t nad, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); /* only add it if its not already in scope */ ns = nad_find_scoped_namespace(nad, uri, NULL); if(ns >= 0) return ns; /* make sure there's mem for us */ NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen); ns = nad->ncur; nad->ncur++; nad->nss[ns].next = nad->scope; nad->scope = ns; nad->nss[ns].luri = strlen(uri); nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri); if(prefix != NULL) { nad->nss[ns].lprefix = strlen(prefix); nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix); } else nad->nss[ns].iprefix = -1; return ns; }
void nad_serialize(nad_t nad, char **buf, int *len) { char *pos; _nad_ptr_check(__func__, nad); *len = sizeof(int) * 5 + /* 4 ints in nad_t, plus one for len */ sizeof(struct nad_elem_st) * nad->ecur + sizeof(struct nad_attr_st) * nad->acur + sizeof(struct nad_ns_st) * nad->ncur + sizeof(char) * nad->ccur; *buf = (char *) malloc(*len); pos = *buf; * (int *) pos = *len; pos += sizeof(int); * (int *) pos = nad->ecur; pos += sizeof(int); * (int *) pos = nad->acur; pos += sizeof(int); * (int *) pos = nad->ncur; pos += sizeof(int); * (int *) pos = nad->ccur; pos += sizeof(int); memcpy(pos, nad->elems, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur; memcpy(pos, nad->attrs, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur; memcpy(pos, nad->nss, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur; memcpy(pos, nad->cdata, sizeof(char) * nad->ccur); }
/** create, update, or zap any matching attr on this elem */ void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen) { int attr; _nad_ptr_check(__func__, nad); /* find one to replace first */ if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0) { /* only create new if there's a value to store */ if(val != NULL) _nad_attr(nad, elem, ns, name, val, vallen); return; } /* got matching, update value or zap */ if(val == NULL) { nad->attrs[attr].lval = nad->attrs[attr].lname = 0; }else{ if(vallen > 0) nad->attrs[attr].lval = vallen; else nad->attrs[attr].lval = strlen(val); nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval); } }
/** declare a namespace on an already-existing element */ int nad_append_namespace(nad_t nad, int elem, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); /* see if its already scoped on this element */ ns = nad_find_namespace(nad, elem, uri, NULL); if(ns >= 0) return ns; /* make some room */ NAD_SAFE(nad->nss, (nad->ncur + 1) * sizeof(struct nad_ns_st), nad->nlen); ns = nad->ncur; nad->ncur++; nad->nss[ns].next = nad->elems[elem].ns; nad->elems[elem].ns = ns; nad->nss[ns].luri = strlen(uri); nad->nss[ns].iuri = _nad_cdata(nad, uri, nad->nss[ns].luri); if(prefix != NULL) { nad->nss[ns].lprefix = strlen(prefix); nad->nss[ns].iprefix = _nad_cdata(nad, prefix, nad->nss[ns].lprefix); } else nad->nss[ns].iprefix = -1; return ns; }
void nad_print(nad_t nad, int elem, const char **xml, int *len) { int ixml = nad->ccur; _nad_ptr_check(__func__, nad); _nad_lp0(nad, elem); *len = nad->ccur - ixml; *xml = nad->cdata + ixml; }
/** find elem using XPath like query * name -- "name" for the child tag of that name * "name/name" for a sub child (recurses) * "?attrib" to match the first tag with that attrib defined * "?attrib=value" to match the first tag with that attrib and value * or any combination: "name/name/?attrib", etc */ int nad_find_elem_path(nad_t nad, int elem, int ns, const char *name) { char *str, *slash, *qmark, *equals; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; /* if it's plain name just search children */ if(strstr(name, "/") == NULL && strstr(name,"?") == NULL) return nad_find_elem(nad, elem, ns, name, 1); str = strdup(name); slash = strstr(str, "/"); qmark = strstr(str, "?"); equals = strstr(str, "="); /* no / in element name part */ if(qmark != NULL && (slash == NULL || qmark < slash)) { /* of type ?attrib */ *qmark = '\0'; qmark++; if(equals != NULL) { *equals = '\0'; equals++; } for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if(strcmp(qmark, "xmlns") == 0) { if(nad_find_namespace(nad, elem, equals, NULL) >= 0) break; } else { if(nad_find_attr(nad, elem, ns, qmark, equals) >= 0) break; } } free(str); return elem; } /* there is a / in element name part - need to recurse */ *slash = '\0'; ++slash; for(elem = nad_find_elem(nad, elem, ns, str, 1); ; elem = nad_find_elem(nad, elem, ns, str, 0)) { if(elem < 0) break; if((elem = nad_find_elem_path(nad, elem, ns, slash)) >= 0) break; } free(str); return elem; }
nad_t nad_deserialize(const char *buf) { nad_t nad = nad_new(); const char *pos = buf + sizeof(int); /* skip len */ _nad_ptr_check(__func__, nad); nad->ecur = * (int *) pos; pos += sizeof(int); nad->acur = * (int *) pos; pos += sizeof(int); nad->ncur = * (int *) pos; pos += sizeof(int); nad->ccur = * (int *) pos; pos += sizeof(int); nad->elen = nad->ecur; nad->alen = nad->acur; nad->nlen = nad->ncur; nad->clen = nad->ccur; if(nad->ecur > 0) { nad->elems = (struct nad_elem_st *) malloc(sizeof(struct nad_elem_st) * nad->ecur); memcpy(nad->elems, pos, sizeof(struct nad_elem_st) * nad->ecur); pos += sizeof(struct nad_elem_st) * nad->ecur; } if(nad->acur > 0) { nad->attrs = (struct nad_attr_st *) malloc(sizeof(struct nad_attr_st) * nad->acur); memcpy(nad->attrs, pos, sizeof(struct nad_attr_st) * nad->acur); pos += sizeof(struct nad_attr_st) * nad->acur; } if(nad->ncur > 0) { nad->nss = (struct nad_ns_st *) malloc(sizeof(struct nad_ns_st) * nad->ncur); memcpy(nad->nss, pos, sizeof(struct nad_ns_st) * nad->ncur); pos += sizeof(struct nad_ns_st) * nad->ncur; } if(nad->ccur > 0) { nad->cdata = (char *) malloc(sizeof(char) * nad->ccur); memcpy(nad->cdata, pos, sizeof(char) * nad->ccur); } return nad; }
/** shove in a new child elem after the given one */ int nad_insert_elem(nad_t nad, int parent, int ns, const char *name, const char *cdata) { int elem; if (parent >= nad->ecur) { if (nad->ecur > 0) parent = nad->ecur -1; else parent = 0; } elem = parent + 1; _nad_ptr_check(__func__, nad); NAD_SAFE(nad->elems, (nad->ecur + 1) * sizeof(struct nad_elem_st), nad->elen); /* relocate all the rest of the elems (unless we're at the end already) */ if(nad->ecur != elem) memmove(&nad->elems[elem + 1], &nad->elems[elem], (nad->ecur - elem) * sizeof(struct nad_elem_st)); nad->ecur++; /* set up req'd parts of new elem */ nad->elems[elem].parent = parent; nad->elems[elem].lname = strlen(name); nad->elems[elem].iname = _nad_cdata(nad,name,nad->elems[elem].lname); nad->elems[elem].attr = -1; nad->elems[elem].ns = nad->scope; nad->scope = -1; nad->elems[elem].itail = nad->elems[elem].ltail = 0; nad->elems[elem].my_ns = ns; /* add cdata if given */ if(cdata != NULL) { nad->elems[elem].lcdata = strlen(cdata); nad->elems[elem].icdata = _nad_cdata(nad,cdata,nad->elems[elem].lcdata); } else { nad->elems[elem].icdata = nad->elems[elem].lcdata = 0; } /* parent/child */ nad->elems[elem].depth = nad->elems[parent].depth + 1; return elem; }
nad_t nad_new(void) { nad_t nad; nad = calloc(1, sizeof(struct nad_st)); nad->scope = -1; #ifdef NAD_DEBUG { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1); } _nad_ptr_check(__func__, nad); #endif return nad; }
/** find a namespace in scope */ int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix) { int ns; _nad_ptr_check(__func__, nad); if(uri == NULL) return -1; for(ns = 0; ns < nad->ncur; ns++) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; } return -1; }
/** remove an element (and its subelements) */ void nad_drop_elem(nad_t nad, int elem) { int next, cur; _nad_ptr_check(__func__, nad); if(elem >= nad->ecur) return; /* find the next elem at this depth to move into the space */ next = elem + 1; while(next < nad->ecur && nad->elems[next].depth > nad->elems[elem].depth) next++; /* relocate */ if(next < nad->ecur) memmove(&nad->elems[elem], &nad->elems[next], (nad->ecur - next) * sizeof(struct nad_elem_st)); nad->ecur -= next - elem; /* relink parents */ for(cur = elem; cur < nad->ecur; cur++) if(nad->elems[cur].parent > next) nad->elems[cur].parent -= (next - elem); }
/** append new cdata to the last elem */ void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth) { int elem = nad->ecur - 1; _nad_ptr_check(__func__, nad); /* make sure this cdata is the child of the last elem to append */ if(nad->elems[elem].depth == depth - 1) { if(nad->elems[elem].icdata == 0) nad->elems[elem].icdata = nad->ccur; _nad_cdata(nad,cdata,len); nad->elems[elem].lcdata += len; return; } /* otherwise, pin the cdata on the tail of the last element at this depth */ elem = nad->depths[depth]; if(nad->elems[elem].itail == 0) nad->elems[elem].itail = nad->ccur; _nad_cdata(nad,cdata,len); nad->elems[elem].ltail += len; }
void nad_free(nad_t nad) { if(nad == NULL) return; #ifdef NAD_DEBUG _nad_ptr_check(__func__, nad); { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_zap(_nad_alloc_tracked, loc); xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad); } #endif /* Free nad */ free(nad->elems); free(nad->attrs); free(nad->cdata); free(nad->nss); free(nad->depths); #ifndef NAD_DEBUG free(nad); #endif }
/** attach new attr to the last elem */ int nad_append_attr(nad_t nad, int ns, const char *name, const char *val) { _nad_ptr_check(__func__, nad); return _nad_attr(nad, nad->ecur - 1, ns, name, val, 0); }
/** insert part of a nad into another nad */ int nad_insert_nad(nad_t dest, int delem, nad_t src, int selem) { int nelem, first, i, j, ns, nattr, attr; char buri[256], *uri = buri, bprefix[256], *prefix = bprefix; _nad_ptr_check(__func__, dest); _nad_ptr_check(__func__, src); /* can't do anything if these aren't real elems */ if(src->ecur <= selem || dest->ecur <= delem) return -1; /* figure out how many elements to copy */ nelem = 1; while(selem + nelem < src->ecur && src->elems[selem + nelem].depth > src->elems[selem].depth) nelem++; /* make room */ NAD_SAFE(dest->elems, (dest->ecur + nelem) * sizeof(struct nad_elem_st), dest->elen); /* relocate all the elems after us */ memmove(&dest->elems[delem + nelem + 1], &dest->elems[delem + 1], (dest->ecur - delem - 1) * sizeof(struct nad_elem_st)); dest->ecur += nelem; /* relink parents on moved elements */ for(i = delem + nelem; i < dest->ecur; i++) if(dest->elems[i].parent > delem) dest->elems[i].parent += nelem; first = delem + 1; /* copy them in, one at a time */ for(i = 0; i < nelem; i++) { /* link the parent */ dest->elems[first + i].parent = delem + (src->elems[selem + i].parent - src->elems[selem].parent); /* depth */ dest->elems[first + i].depth = dest->elems[delem].depth + (src->elems[selem + i].depth - src->elems[selem].depth) + 1; /* name */ dest->elems[first + i].lname = src->elems[selem + i].lname; dest->elems[first + i].iname = _nad_cdata(dest, src->cdata + src->elems[selem + i].iname, src->elems[selem + i].lname); /* cdata */ dest->elems[first + i].lcdata = src->elems[selem + i].lcdata; dest->elems[first + i].icdata = _nad_cdata(dest, src->cdata + src->elems[selem + i].icdata, src->elems[selem + i].lcdata); dest->elems[first + i].ltail = src->elems[selem + i].ltail; dest->elems[first + i].itail = _nad_cdata(dest, src->cdata + src->elems[selem + i].itail, src->elems[selem + i].ltail); /* namespaces */ dest->elems[first + i].my_ns = dest->elems[first + i].ns = dest->scope = -1; /* first, the element namespace */ ns = src->elems[selem + i].my_ns; if(ns >= 0) { for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) { dest->elems[first + i].my_ns = j; break; } /* not found, gotta add it */ if(j == dest->ncur) { /* make room */ /* !!! this can go once we have _ex() functions */ if(NAD_NURI_L(src, ns) > 255) uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); if(NAD_NPREFIX_L(src, ns) > 255) prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns)); if(NAD_NPREFIX_L(src, ns) > 0) { sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns)); dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, prefix); } else dest->elems[first + i].my_ns = nad_add_namespace(dest, uri, NULL); if(uri != buri) free(uri); if(prefix != bprefix) free(prefix); } } /* then, any declared namespaces */ for(ns = src->elems[selem + i].ns; ns >= 0; ns = src->nss[ns].next) { for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) break; /* not found, gotta add it */ if(j == dest->ncur) { /* make room */ /* !!! this can go once we have _ex() functions */ if(NAD_NURI_L(src, ns) > 255) uri = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); if(NAD_NPREFIX_L(src, ns) > 255) prefix = (char *) malloc(sizeof(char) * (NAD_NURI_L(src, ns) + 1)); sprintf(uri, "%.*s", NAD_NURI_L(src, ns), NAD_NURI(src, ns)); if(NAD_NPREFIX_L(src, ns) > 0) { sprintf(prefix, "%.*s", NAD_NPREFIX_L(src, ns), NAD_NPREFIX(src, ns)); nad_add_namespace(dest, uri, prefix); } else nad_add_namespace(dest, uri, NULL); if(uri != buri) free(uri); if(prefix != bprefix) free(prefix); } } /* scope any new namespaces onto this element */ dest->elems[first + i].ns = dest->scope; dest->scope = -1; /* attributes */ dest->elems[first + i].attr = -1; if(src->acur > 0) { nattr = 0; for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) nattr++; /* make room */ NAD_SAFE(dest->attrs, (dest->acur + nattr) * sizeof(struct nad_attr_st), dest->alen); /* kopy ker-azy! */ for(attr = src->elems[selem + i].attr; attr >= 0; attr = src->attrs[attr].next) { /* name */ dest->attrs[dest->acur].lname = src->attrs[attr].lname; dest->attrs[dest->acur].iname = _nad_cdata(dest, src->cdata + src->attrs[attr].iname, src->attrs[attr].lname); /* val */ dest->attrs[dest->acur].lval = src->attrs[attr].lval; dest->attrs[dest->acur].ival = _nad_cdata(dest, src->cdata + src->attrs[attr].ival, src->attrs[attr].lval); /* namespace */ dest->attrs[dest->acur].my_ns = -1; ns = src->attrs[attr].my_ns; if(ns >= 0) for(j = 0; j < dest->ncur; j++) if(NAD_NURI_L(src, ns) == NAD_NURI_L(dest, j) && strncmp(NAD_NURI(src, ns), NAD_NURI(dest, j), NAD_NURI_L(src, ns)) == 0) { dest->attrs[dest->acur].my_ns = j; break; } /* link it up */ dest->attrs[dest->acur].next = dest->elems[first + i].attr; dest->elems[first + i].attr = dest->acur; dest->acur++; } } } return first; }