src/server/webdav/xml.c

branch
webdav
changeset 223
bbaec8415c10
parent 211
2160585200ac
child 224
0de1ec82628e
--- 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;
+}
+

mercurial