Exemple #1
0
/** 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;
}
Exemple #2
0
/** 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;
}
Exemple #3
0
/** 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;
}
Exemple #4
0
/** 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;
}
Exemple #5
0
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;
}
Exemple #6
0
/** 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;
}
Exemple #7
0
/** 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;
}
Exemple #8
0
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);
}
Exemple #9
0
/** 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);
    }

}
Exemple #10
0
/** 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;
}
Exemple #11
0
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;
}
Exemple #12
0
/** 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;
}
Exemple #13
0
Fichier : nad.c Projet : zipo/zipo
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;
}
Exemple #14
0
Fichier : nad.c Projet : zipo/zipo
/** 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;
}
Exemple #15
0
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;
}
Exemple #16
0
/** 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;
}
Exemple #17
0
/** 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);
}
Exemple #18
0
/** 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;
}
Exemple #19
0
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
}
Exemple #20
0
/** 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);
}
Exemple #21
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;
}