示例#1
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;
}
示例#2
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;
}
示例#3
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;
}
示例#4
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;
}
示例#5
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;
}
示例#6
0
/** internal: append some cdata and return the index to it */
static int _nad_cdata(nad_t nad, const char *cdata, int len)
{
    NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);

    memcpy(nad->cdata + nad->ccur, cdata, len);
    nad->ccur += len;
    return nad->ccur - len;
}
示例#7
0
文件: nad.c 项目: 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;
}
示例#8
0
/** internal: create a new attr on any given elem */
static int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
{
    int attr;

    /* make sure there's mem for us */
    NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen);

    attr = nad->acur;
    nad->acur++;
    nad->attrs[attr].next = nad->elems[elem].attr;
    nad->elems[elem].attr = attr;
    nad->attrs[attr].lname = strlen(name);
    nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname);
    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);
    nad->attrs[attr].my_ns = ns;

    return attr;
}
示例#9
0
/** internal recursive printing function */
static int _nad_lp0(nad_t nad, int elem)
{
    int attr;
    int ndepth;
    int ns;
    int elem_ns;

    /* there's a lot of code in here, but don't let that scare you, it's just duplication in order to be a bit more efficient cpu-wise */

    /* this whole thing is in a big loop for processing siblings */
    while(elem != nad->ecur)
    {

    /* make enough space for the opening element */
    ns = nad->elems[elem].my_ns;
    if(ns >= 0 && nad->nss[ns].iprefix >= 0)
    {
        NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + nad->nss[ns].lprefix + 2, nad->clen);
    } else {
        NAD_SAFE(nad->cdata, nad->ccur + nad->elems[elem].lname + 1, nad->clen);
    }

    /* opening tag */
    *(nad->cdata + nad->ccur++) = '<';

    /* add the prefix if necessary */
    if(ns >= 0 && nad->nss[ns].iprefix >= 0)
    {
        memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
        nad->ccur += nad->nss[ns].lprefix;
        *(nad->cdata + nad->ccur++) = ':';
    }

    /* copy in the name */
    memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
    nad->ccur += nad->elems[elem].lname;

    /* add element prefix namespace */
    ns = nad->elems[elem].my_ns;
    if(ns >= 0 && nad->nss[ns].iprefix >= 0)
    {
        /* make space */
        if(nad->nss[ns].iprefix >= 0)
        {
            NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
        } else {
            NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
        }

        /* start */
        memcpy(nad->cdata + nad->ccur, " xmlns", 6);
        nad->ccur += 6;

        /* prefix if necessary */
        if(nad->nss[ns].iprefix >= 0)
        {
            *(nad->cdata + nad->ccur++) = ':';
            memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
            nad->ccur += nad->nss[ns].lprefix;
        }

        *(nad->cdata + nad->ccur++) = '=';
        *(nad->cdata + nad->ccur++) = '\'';

        /* uri */
        memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
        nad->ccur += nad->nss[ns].luri;

        *(nad->cdata + nad->ccur++) = '\'';

        elem_ns = ns;
    }else{
        elem_ns = -1;
    }

    /* add the namespaces */
    for(ns = nad->elems[elem].ns; ns >= 0; ns = nad->nss[ns].next)
    {
        /* never explicitly declare the implicit xml namespace */
        if(nad->nss[ns].luri == strlen(uri_XML) && strncmp(uri_XML, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri) == 0)
            continue;

        /* do not redeclare element namespace */
        if(ns == elem_ns)
            continue;

        /* make space */
        if(nad->nss[ns].iprefix >= 0)
        {
            NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + nad->nss[ns].lprefix + 10, nad->clen);
        } else {
            NAD_SAFE(nad->cdata, nad->ccur + nad->nss[ns].luri + 9, nad->clen);
        }

        /* start */
        memcpy(nad->cdata + nad->ccur, " xmlns", 6);
        nad->ccur += 6;

        /* prefix if necessary */
        if(nad->nss[ns].iprefix >= 0)
        {
            *(nad->cdata + nad->ccur++) = ':';
            memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
            nad->ccur += nad->nss[ns].lprefix;
        }

        *(nad->cdata + nad->ccur++) = '=';
        *(nad->cdata + nad->ccur++) = '\'';

        /* uri */
        memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iuri, nad->nss[ns].luri);
        nad->ccur += nad->nss[ns].luri;

        *(nad->cdata + nad->ccur++) = '\'';
    }

    for(attr = nad->elems[elem].attr; attr >= 0; attr = nad->attrs[attr].next)
    {
        if(nad->attrs[attr].lname <= 0) continue;

        /* make enough space for the wrapper part */
        ns = nad->attrs[attr].my_ns;
        if(ns >= 0 && nad->nss[ns].iprefix >= 0)
        {
            NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + nad->nss[ns].lprefix + 4, nad->clen);
        } else {
            NAD_SAFE(nad->cdata, nad->ccur + nad->attrs[attr].lname + 3, nad->clen);
        }

        *(nad->cdata + nad->ccur++) = ' ';

        /* add the prefix if necessary */
        if(ns >= 0 && nad->nss[ns].iprefix >= 0)
        {
            memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
            nad->ccur += nad->nss[ns].lprefix;
            *(nad->cdata + nad->ccur++) = ':';
        }

        /* copy in the name parts */
        memcpy(nad->cdata + nad->ccur, nad->cdata + nad->attrs[attr].iname, nad->attrs[attr].lname);
        nad->ccur += nad->attrs[attr].lname;
        *(nad->cdata + nad->ccur++) = '=';
        *(nad->cdata + nad->ccur++) = '\'';

        /* copy in the escaped value */
        _nad_escape(nad, nad->attrs[attr].ival, nad->attrs[attr].lval, 4);

        /* make enough space for the closing quote and add it */
        NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
        *(nad->cdata + nad->ccur++) = '\'';
    }

    /* figure out what's next */
    if(elem+1 == nad->ecur)
        ndepth = -1;
    else
        ndepth = nad->elems[elem+1].depth;

    /* handle based on if there are children, update nelem after done */
    if(ndepth <= nad->elems[elem].depth)
    {
        /* make sure there's enough for what we could need */
        NAD_SAFE(nad->cdata, nad->ccur + 2, nad->clen);
        if(nad->elems[elem].lcdata == 0)
        {
            memcpy(nad->cdata + nad->ccur, "/>", 2);
            nad->ccur += 2;
        }else{
            *(nad->cdata + nad->ccur++) = '>';

            /* copy in escaped cdata */
            _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata,4);

            /* make room */
            ns = nad->elems[elem].my_ns;
            if(ns >= 0 && nad->nss[ns].iprefix >= 0)
            {
                NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
            } else {
                NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
            }

            /* close tag */
            memcpy(nad->cdata + nad->ccur, "</", 2);
            nad->ccur += 2;

            /* add the prefix if necessary */
            if(ns >= 0 && nad->nss[ns].iprefix >= 0)
            {
                memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
                nad->ccur += nad->nss[ns].lprefix;
                *(nad->cdata + nad->ccur++) = ':';
            }

            memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
            nad->ccur += nad->elems[elem].lname;
            *(nad->cdata + nad->ccur++) = '>';
        }

        /* always try to append the tail */
        _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);

        /* if no siblings either, bail */
        if(ndepth < nad->elems[elem].depth)
            return elem+1;

        /* next sibling */
        elem++;
    }else{
        int nelem;
        /* process any children */

        /* close ourself and append any cdata first */
        NAD_SAFE(nad->cdata, nad->ccur + 1, nad->clen);
        *(nad->cdata + nad->ccur++) = '>';
        _nad_escape(nad, nad->elems[elem].icdata, nad->elems[elem].lcdata, 4);

        /* process children */
        nelem = _nad_lp0(nad, elem+1);

        /* close and tail up */
        ns = nad->elems[elem].my_ns;
        if(ns >= 0 && nad->nss[ns].iprefix >= 0)
        {
            NAD_SAFE(nad->cdata, nad->ccur + 4 + nad->elems[elem].lname + nad->nss[ns].lprefix, nad->clen);
        } else {
            NAD_SAFE(nad->cdata, nad->ccur + 3 + nad->elems[elem].lname, nad->clen);
        }
        memcpy(nad->cdata + nad->ccur, "</", 2);
        nad->ccur += 2;
        if(ns >= 0 && nad->nss[ns].iprefix >= 0)
        {
            memcpy(nad->cdata + nad->ccur, nad->cdata + nad->nss[ns].iprefix, nad->nss[ns].lprefix);
            nad->ccur += nad->nss[ns].lprefix;
            *(nad->cdata + nad->ccur++) = ':';
        }
        memcpy(nad->cdata + nad->ccur, nad->cdata + nad->elems[elem].iname, nad->elems[elem].lname);
        nad->ccur += nad->elems[elem].lname;
        *(nad->cdata + nad->ccur++) = '>';
        _nad_escape(nad, nad->elems[elem].itail, nad->elems[elem].ltail,4);

        /* if the next element is not our sibling, we're done */
        if(nelem < nad->ecur && nad->elems[nelem].depth < nad->elems[elem].depth)
            return nelem;

        /* for next sibling in while loop */
        elem = nelem;
    }

    /* here's the end of that big while loop */
    }

    return elem;
}
示例#10
0
static void _nad_escape(nad_t nad, int data, int len, int flag)
{
    char *c;
    int ic;

    if(len <= 0) return;

    /* first, if told, find and escape " */
    while(flag >= 4 && (c = memchr(nad->cdata + data,'"',len)) != NULL)
    {
        /* get offset */
        ic = c - nad->cdata;

        /* cute, eh?  handle other data before this normally */
        _nad_escape(nad, data, ic - data, 3);

        /* ensure enough space, and add our escaped &quot; */
        NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
        memcpy(nad->cdata + nad->ccur, "&quot;", 6);
        nad->ccur += 6;

        /* just update and loop for more */
        len -= (ic+1) - data;
        data = ic+1;
    }

    /* next, find and escape ' */
    while(flag >= 3 && (c = memchr(nad->cdata + data,'\'',len)) != NULL)
    {
        ic = c - nad->cdata;
        _nad_escape(nad, data, ic - data, 2);

        /* ensure enough space, and add our escaped &apos; */
        NAD_SAFE(nad->cdata, nad->ccur + 6, nad->clen);
        memcpy(nad->cdata + nad->ccur, "&apos;", 6);
        nad->ccur += 6;

        /* just update and loop for more */
        len -= (ic+1) - data;
        data = ic+1;
    }

    /* next look for < */
    while(flag >= 2 && (c = memchr(nad->cdata + data,'<',len)) != NULL)
    {
        ic = c - nad->cdata;
        _nad_escape(nad, data, ic - data, 1);

        /* ensure enough space, and add our escaped &lt; */
        NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
        memcpy(nad->cdata + nad->ccur, "&lt;", 4);
        nad->ccur += 4;

        /* just update and loop for more */
        len -= (ic+1) - data;
        data = ic+1;
    }

    /* next look for > */
    while(flag >= 1 && (c = memchr(nad->cdata + data, '>', len)) != NULL)
    {
        ic = c - nad->cdata;
        _nad_escape(nad, data, ic - data, 0);

        /* ensure enough space, and add our escaped &gt; */
        NAD_SAFE(nad->cdata, nad->ccur + 4, nad->clen);
        memcpy(nad->cdata + nad->ccur, "&gt;", 4);
        nad->ccur += 4;

        /* just update and loop for more */
        len -= (ic+1) - data;
        data = ic+1;
    }

    /* if & is found, escape it */
    while((c = memchr(nad->cdata + data,'&',len)) != NULL)
    {
        ic = c - nad->cdata;

        /* ensure enough space */
        NAD_SAFE(nad->cdata, nad->ccur + 5 + (ic - data), nad->clen);

        /* handle normal data */
        memcpy(nad->cdata + nad->ccur, nad->cdata + data, (ic - data));
        nad->ccur += (ic - data);

        /* append escaped &amp; */
        memcpy(nad->cdata + nad->ccur, "&amp;", 5);
        nad->ccur += 5;

        /* just update and loop for more */
        len -= (ic+1) - data;
        data = ic+1;
    }

    /* nothing exciting, just append normal cdata */
    if(len > 0) {
        NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen);
        memcpy(nad->cdata + nad->ccur, nad->cdata + data, len);
        nad->ccur += len;
    }
}
示例#11
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;
}