--- a/src/server/webdav/xml.c Tue Jan 14 20:05:18 2020 +0100 +++ b/src/server/webdav/xml.c Tue Jan 14 22:05:34 2020 +0100 @@ -30,7 +30,116 @@ #include <stdlib.h> #include <string.h> + #include "xml.h" +typedef struct StackElm { + WSXmlNode *node; // list of nodes + WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL + struct StackElm *next; +} StackElm; +#define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm; +int wsxml_iterator( + pool_handle_t *pool, + WSXmlNode *node, + wsxml_func begincb, + wsxml_func endcb, + void *udata) +{ + if(!node) { + return 0; + } + + StackElm *stack = pool_malloc(pool, sizeof(StackElm)); + if(!stack) { + return 1; // OOM + } + stack->next = NULL; + stack->node = node; + stack->parent = NULL; + + int ret = 0; + int br = 0; + while(stack) { + StackElm *cur = stack; + WSXmlNode *xmlnode = cur->node; // get top stack element + stack = cur->next; // and remove it + cur->next = NULL; + + while(xmlnode) { + // element begin callback + if(begincb(xmlnode, udata)) { + br = 1; + break; // I don't like break with labels - is this wrong? + } + + if(xmlnode->children) { + // put the children on the stack + // the next stack iteration will process the children + StackElm *newelm = pool_malloc(pool, sizeof(StackElm)); + if(!newelm) { + ret = 1; + br = 1; + break; + } + newelm->next = NULL; + newelm->node = xmlnode->children; + // setting the parent will make sure endcb will be called + // for the current xmlnode after all children are processed + newelm->parent = xmlnode; + + // if xmlnode->next is not NULL, there are still nodes at + // this level, therefore we have to put these also on the + // stack + // this way, the remaining nodes are processed after all + // children of the current node are processed + if(xmlnode->next) { + // reuse current StackElm + cur->node = xmlnode->next; + STACK_PUSH(stack, cur); + cur = NULL; + } + + // now we can put the children on the stack + STACK_PUSH(stack, newelm); + // break, because we don't want to process xmlnode->next now + break; + } else { + // no children means, the end callback can be called directly + // after the begin callback (no intermediate nodes) + if(endcb(xmlnode, udata)) { + br = 1; + break; + } + } + + // continue with next node at this level + xmlnode = xmlnode->next; + } + if(br) { + break; // break because of an error + } + + if(cur) { + if(cur->parent) { + if(endcb(cur->parent, udata)) { + break; + } + } + pool_free(pool, cur); + } + } + + // free all remaining elements + StackElm *elm = stack; + while(elm) { + StackElm *next = elm->next; + pool_free(pool, elm); + elm = next; + } + + return ret; +} +