dav/tags.c

changeset 747
efbd59642577
parent 667
6cdcd3e4e368
child 767
f4acc783f25e
--- a/dav/tags.c	Sun Apr 16 14:12:24 2023 +0200
+++ b/dav/tags.c	Fri Apr 21 21:25:32 2023 +0200
@@ -31,8 +31,10 @@
 #include <string.h>
 #include <ctype.h>
 
-#include <ucx/string.h>
-#include <ucx/utils.h>
+#include <cx/string.h>
+#include <cx/utils.h>
+#include <cx/printf.h>
+#include <cx/hash_map.h>
 
 #include <libidav/crypto.h>
 
@@ -52,50 +54,53 @@
     free(tag);
 }
 
-void free_taglist(UcxList *list) {
-    ucx_list_free_content(list, (ucx_destructor)free_dav_tag);
-    ucx_list_free(list);
+void free_taglist(CxList *list) {
+    if(!list) {
+        return;
+    }
+    cxListDestroy(list);
 }
 
 int compare_tagname(DavTag* left, DavTag* right, void* ignorecase) {
-    sstr_t leftname = sstr(left->name);
-    sstr_t rightname = sstr(right->name);
+    cxstring leftname = cx_str(left->name);
+    cxstring rightname = cx_str(right->name);
     if (ignorecase && *((int*) ignorecase)) {
-        return sstrcasecmp(leftname, rightname);
+        return cx_strcasecmp(leftname, rightname);
     } else {
-        return sstrcmp(leftname, rightname);
+        return cx_strcmp(leftname, rightname);
     }
 }
 
-UcxList* parse_text_taglist(const char *buf, size_t length) {
-    UcxList *tags = NULL;
+CxList* parse_text_taglist(const char *buf, size_t length) {
+    CxList *tags = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    tags->simple_destructor = (cx_destructor_func)free_dav_tag;
     
     int line_start = 0;
     for(int i=0;i<length;i++) {
         if(buf[i] == '\n' || i == length-1) {
-            sstr_t line = sstrtrim(sstrn((char*)buf + line_start, i - line_start));
+            cxstring line = cx_strtrim(cx_strn((char*)buf + line_start, i - line_start));
             if(line.length > 0) {
                 DavTag *tag = calloc(1, sizeof(DavTag));
-                sstr_t color = sstrchr(line, '#');
+                cxstring color = cx_strchr(line, '#');
                 if(color.length>0) {
-                    sstr_t name = line;
+                    cxstring name = line;
                     name.length = (int)(color.ptr-line.ptr);
                     if(name.length != 0) {
-                        tag->name = sstrdup(name).ptr;
+                        tag->name = cx_strdup(name).ptr;
                         color.ptr++;
                         color.length--;
                         if(color.length > 0) {
-                            tag->color = sstrdup(color).ptr;
+                            tag->color = cx_strdup(color).ptr;
                         }
                     } else {
                         free(tag);
                     }
                 } else {
-                    tag->name = sstrdup(line).ptr;
+                    tag->name = cx_strdup(line).ptr;
                     tag->color = NULL;
                 }
                 
-                tags = ucx_list_append(tags, tag);
+                cxListAdd(tags, tag);
             }
             line_start = i+1;
         }
@@ -104,55 +109,61 @@
     return tags;
 }
 
-UcxBuffer* create_text_taglist(UcxList *tags) {
+CxMap* taglist2map(CxList *tags) {
+    CxMap *map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, tags->size + 8);
+    CxIterator iter = cxListIterator(tags);
+    cx_foreach(DavTag*, t, iter) {
+        cxMapPut(map, cx_hash_key_str(t->name), t);
+    }
+    return map;
+}
+
+CxBuffer* create_text_taglist(CxList *tags) {
     if(!tags) {
         return NULL;
     }
     
-    UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
-    UCX_FOREACH(elm, tags) {
-        DavTag *tag = elm->data;
+    CxBuffer *buf = cxBufferCreate(NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag *, tag, i) {
         if(tag->color) {
-            ucx_bprintf(buf, "%s#%s\n", tag->name, tag->color);
+            cx_bprintf(buf, "%s#%s\n", tag->name, tag->color);
         } else {
-            ucx_bprintf(buf, "%s\n", tag->name);
+            cx_bprintf(buf, "%s\n", tag->name);
         }
     }
     return buf;
 }
 
 
-UcxList* parse_csv_taglist(const char *buf, size_t length) {
-    UcxList *taglist = NULL;
+CxList* parse_csv_taglist(const char *buf, size_t length) {
+    CxList *taglist = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    taglist->simple_destructor = (cx_destructor_func)free_dav_tag;
     
-    sstr_t str = sstrn((char*)buf, length);
-    ssize_t count = 0;
-    sstr_t *tags = sstrsplit(str, S(","), &count);
-    for(int i=0;i<count;i++) {
-        sstr_t trimmed_tag = sstrtrim(tags[i]);
+    cxstring str = cx_strn(buf, length);
+    CxStrtokCtx tags = cx_strtok(str, CX_STR(","), INT_MAX);
+    cxstring tagstr;
+    while(cx_strtok_next(&tags, &tagstr)) {
+        cxstring trimmed_tag = cx_strtrim(tagstr);
         if (trimmed_tag.length > 0) {
             DavTag *tag = malloc(sizeof(DavTag));
-            tag->name = sstrdup(trimmed_tag).ptr;
+            tag->name = cx_strdup(trimmed_tag).ptr;
             tag->color = NULL;
-            taglist = ucx_list_append(taglist, tag);
+            cxListAdd(taglist, tag);
         }
-        free(tags[i].ptr);
-    }
-    if(tags) {
-        free(tags);
     }
     return taglist;
 }
 
-UcxBuffer* create_csv_taglist(UcxList *tags) {
-    UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
+CxBuffer* create_csv_taglist(CxList *tags) {
+    CxBuffer *buf = cxBufferCreate(NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     int insertsep = 0;
-    UCX_FOREACH(elm, tags) {
-        DavTag *tag = elm->data;
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag*, tag, i) {
         if(insertsep) {
-            ucx_buffer_putc(buf, ',');
+            cxBufferPut(buf, ',');
         }
-        ucx_buffer_puts(buf, tag->name);
+        cxBufferPutString(buf, tag->name);
         insertsep = 1;
     }
     return buf;
@@ -196,8 +207,9 @@
     return tag;
 } 
 
-UcxList* parse_dav_xml_taglist(DavXmlNode *taglistnode) {
-    UcxList *tags = NULL;
+CxList* parse_dav_xml_taglist(DavXmlNode *taglistnode) {
+    CxList *tags = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    tags->simple_destructor = (cx_destructor_func)free_dav_tag;
     
     DavXmlNode *node = taglistnode;
     while(node) {
@@ -205,7 +217,7 @@
             if(!strcmp(node->namespace, DAV_PROPS_NS) && !strcmp(node->name, "tag")) {
                 DavTag *tag = parse_xml_dav_tag(node);
                 if(tag) {
-                    tags = ucx_list_append(tags, tag);
+                    cxListAdd(tags, tag);
                 }
             }
         } 
@@ -215,12 +227,11 @@
     return tags;
 }
 
-DavXmlNode* create_xml_taglist(UcxList *tags) {
+DavXmlNode* create_xml_taglist(CxList *tags) {
     DavXmlNode *tag1 = NULL;
     DavXmlNode *lasttag = NULL;
-    UCX_FOREACH(elm, tags) {
-        DavTag *tag = elm->data;
-        
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag*, tag, i) {
         DavXmlNode *tagelm = dav_xml_createnode(DAV_PROPS_NS, "tag");
         DavXmlNode *tagname = dav_xml_createnode_with_text(DAV_PROPS_NS, "name", tag->name);
         tagelm->children = tagname;
@@ -278,8 +289,9 @@
     return tag;
 }
 
-UcxList* parse_macos_taglist(const char *buf, size_t length) {
-    UcxList *taglist = NULL;
+CxList* parse_macos_taglist(const char *buf, size_t length) {
+    CxList *taglist = cxLinkedListCreate(CX_STORE_POINTERS);
+    taglist->simple_destructor = (cx_destructor_func)free_dav_tag;
     
     CFDataRef data = CFDataCreateWithBytesNoCopy(
             kCFAllocatorDefault,
@@ -297,7 +309,7 @@
         if(CFStringGetCString(str, cstr, cstrbuflen, kCFStringEncodingUTF8)) {
             DavTag *tag = tagstr2davtag(cstr);
             if(tag) {
-                taglist = ucx_list_append(taglist, tag);
+                cxListAdd(taglist, tag);
             }
         }
         free(cstr);
@@ -309,7 +321,7 @@
     return taglist;
 }
 
-UcxBuffer* create_macos_taglist(UcxList *tags) {
+CxBuffer* create_macos_taglist(CxList *tags) {
     size_t count = ucx_list_size(tags);
     if(count == 0) {
         return NULL;
@@ -317,8 +329,8 @@
     
     CFStringRef *strings = calloc(sizeof(CFStringRef), count);
     int i = 0;
-    UCX_FOREACH(elm, tags) {
-        DavTag *tag = elm->data;
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag*, tag, i) {
         CFStringRef str = NULL;
         if(tag->color) {
             sstr_t s = sstrcat(3, sstr(tag->name), S("\n"), sstr(tag->color));
@@ -334,13 +346,13 @@
     CFPropertyListRef array = CFArrayCreate(kCFAllocatorDefault, (const void**)strings, count, &kCFTypeArrayCallBacks);
     CFDataRef data = CFPropertyListCreateData(kCFAllocatorDefault, array, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
     
-    UcxBuffer *buf = NULL;
+    CxBuffer *buf = NULL;
     if(data) {
         int datalen = CFDataGetLength(data);
         CFRange range;
         range.location = 0;
         range.length = datalen;
-        buf = ucx_buffer_new(NULL, datalen, 0);
+        buf = cxBufferCreate(NULL, datalen, cxDefaultAllocator, 0);
         CFDataGetBytes(data, range, (UInt8*)buf->space);
         buf->size = datalen;
         CFRelease(data);
@@ -355,18 +367,18 @@
 }
 
 #else
-UcxList* parse_macos_taglist(const char *buf, size_t length) {
+CxList* parse_macos_taglist(const char *buf, size_t length) {
     fprintf(stderr, "Error: macos tags not supported on this platform.\n");
     return NULL;
 }
-UcxBuffer* create_macos_taglist(UcxList *tags) {
+CxBuffer* create_macos_taglist(CxList *tags) {
     fprintf(stderr, "Error: macos tags not supported on this platform.\n");
     return NULL;
 }
 #endif
 
 
-int compare_taglists(UcxList *tags1, UcxList *tags2) {
+int compare_taglists(CxList *tags1, CxList *tags2) {
     if(!tags1) {
         return tags2 ? 0 : 1;
     }
@@ -374,100 +386,93 @@
         return tags1 ? 0 : 1;
     }
     
-    UcxMap *map1 = ucx_map_new(32);
-    UCX_FOREACH(elm, tags1) {
-        DavTag *t = elm->data;
-        ucx_map_cstr_put(map1, t->name, t);
-    }
+    CxMap *map1 = taglist2map(tags1);
     
     int equal = 1;
     int i = 0;
-    UCX_FOREACH(elm, tags2) {
-        DavTag *t = elm->data;
-        if(!ucx_map_cstr_get(map1, t->name)) {
+    CxIterator iter = cxListIterator(tags2);
+    cx_foreach(DavTag*, t, iter) {
+        if(!cxMapGet(map1, cx_hash_key_str(t->name))) {
             equal = 0;
             break;
         }
         i++;
     }
     
-    if(i != map1->count) {
+    if(i != map1->size) {
         equal = 0;
     }
-    ucx_map_free(map1);
+    cxMapDestroy(map1);
     return equal;
 }
 
-char* create_tags_hash(UcxList *tags) {
+char* create_tags_hash(CxList *tags) {
     if(!tags) {
         return NULL;
     }
-    UcxBuffer *buf = create_text_taglist(tags);
+    CxBuffer *buf = create_text_taglist(tags);
     char *hash = dav_create_hash(buf->space, buf->size);
-    ucx_buffer_free(buf);
+    cxBufferDestroy(buf);
     return hash;
 }
 
-UcxList* merge_tags(UcxList *tags1, UcxList *tags2) {
+CxList* merge_tags(CxList *tags1, CxList *tags2) {
     // this map is used to check the existence of tags
-    UcxMap *tag_map = ucx_map_new(32);
+    CxMap *tag_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 32);
     // merged taglist
-    UcxList *new_tags = NULL;
+    CxList *new_tags = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    new_tags->simple_destructor = (cx_destructor_func)free_dav_tag;
 
     // add all local tags
-    UCX_FOREACH(elm, tags1) {
-        DavTag *t = elm->data;
-        ucx_map_cstr_put(tag_map, t->name, t);
+    CxIterator iter = cxListIterator(tags1);
+    cx_foreach(DavTag*, t, iter) {
+        cxMapPut(tag_map, cx_hash_key_str(t->name), t);
         DavTag *newt = calloc(1, sizeof(DavTag));
         newt->color = t->color ? strdup(t->color) : NULL;
         newt->name = strdup(t->name);
-        new_tags = ucx_list_append(new_tags, newt);
+        cxListAdd(new_tags, newt);
     }
     // check if a remote tag is already in the map
     // and if not add it to the new taglist
-    UCX_FOREACH(elm, tags2) {
-        DavTag *t = elm->data;
-        if(!ucx_map_cstr_get(tag_map, t->name)) {
+    iter = cxListIterator(tags2);
+    cx_foreach(DavTag*, t, iter) {
+        if(!cxMapGet(tag_map, cx_hash_key_str(t->name))) {
             DavTag *newt = calloc(1, sizeof(DavTag));
             newt->color = t->color ? strdup(t->color) : NULL;
             newt->name = strdup(t->name);
-            new_tags = ucx_list_append(new_tags, newt);
+            cxListAdd(new_tags, newt);
         }
     }
 
-    ucx_map_free(tag_map);
+    cxMapDestroy(tag_map);
 
     return new_tags;
 }
 
-void add_tag_colors(UcxList *taglist, UcxList *colored) {
-    UcxMap *tagmap = ucx_map_new(32);
-    UCX_FOREACH(elm, taglist) {
-        DavTag *tag = elm->data;
-        ucx_map_cstr_put(tagmap, tag->name, tag);
-    }
+void add_tag_colors(CxList *taglist, CxList *colored) {
+    CxMap *tagmap = taglist2map(taglist);
     
-    UCX_FOREACH(elm, colored) {
-        DavTag *colored_tag = elm->data;
+    CxIterator i = cxListIterator(colored);
+    cx_foreach(DavTag*, colored_tag, i) {
         if(colored_tag->color) {
-            DavTag *tag = ucx_map_cstr_get(tagmap, colored_tag->name);
+            DavTag *tag = cxMapGet(tagmap, cx_hash_key_str(colored_tag->name));
             if(tag && !tag->color) {
                 tag->color = strdup(colored_tag->color);
             }
         }
     }
     
-    ucx_map_free(tagmap);
+    cxMapDestroy(tagmap);
 }
 
 /* ----------- ----------- tag filter  ---------------------- */
 
-static size_t rtrimskip(scstr_t str, size_t skip) {
+static size_t rtrimskip(cxstring str, size_t skip) {
     while (skip < str.length && isspace(str.ptr[skip])) skip++;
     return skip;
 }
 
-static size_t parse_tagfilter_taglist(scstr_t fs, SyncTagFilter* tagfilter) {
+static size_t parse_tagfilter_taglist(cxstring fs, SyncTagFilter* tagfilter) {
     size_t csvlen;
     for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) {
         if (fs.ptr[csvlen] == ')') break;
@@ -479,12 +484,12 @@
     return csvlen;
 }
 
-static size_t parse_tagfilter_subfilters(scstr_t fs, SyncTagFilter* tagfilter);
+static size_t parse_tagfilter_subfilters(cxstring fs, SyncTagFilter* tagfilter);
 
-static size_t parse_tagfilter_filter(scstr_t fs, SyncTagFilter* tagfilter) {
+static size_t parse_tagfilter_filter(cxstring fs, SyncTagFilter* tagfilter) {
     
     size_t consumed = rtrimskip(fs, 0);
-    fs = scstrsubs(fs, consumed);
+    fs = cx_strsubs(fs, consumed);
     
     if (fs.length == 0) {
         return consumed;
@@ -512,7 +517,7 @@
         if (hasop) {
             size_t skip = rtrimskip(fs, 1);
             consumed += skip;
-            fs = scstrsubs(fs, skip);
+            fs = cx_strsubs(fs, skip);
         }
 
         if (fs.length > 0 && fs.ptr[0] == '(') {
@@ -533,7 +538,7 @@
 /*
  * Parses:  ( "(" , filter , ")" )+
  */
-static size_t parse_tagfilter_subfilters(scstr_t fs, SyncTagFilter* f) {
+static size_t parse_tagfilter_subfilters(cxstring fs, SyncTagFilter* f) {
     
     // strategy: allocate much and give back later (instead of reallocs in loop)
     size_t subfilter_cap = 8;
@@ -545,7 +550,7 @@
     do {
         // skip leading parenthesis (and white spaces)
         c = rtrimskip(fs, 1);
-        fs = scstrsubs(fs, c);
+        fs = cx_strsubs(fs, c);
         total_consumed += c;
     
         // increase array capacity, if necessary
@@ -572,7 +577,7 @@
             
             // consume ')' and find the next parenthesis or the end-of-string
             c = rtrimskip(fs, 1+c);
-            fs = scstrsubs(fs, c);
+            fs = cx_strsubs(fs, c);
             total_consumed += c;
 
             if (fs.length == 0 || fs.ptr[0] == ')') {
@@ -611,7 +616,7 @@
         return tagfilter;
     }
     
-    scstr_t fs = scstr(filterstring);
+    cxstring fs = cx_str(filterstring);
     size_t consumed = parse_tagfilter_filter(fs, tagfilter);
     if (!consumed) {
         free_tagfilter(tagfilter);
@@ -639,42 +644,55 @@
 }
 
 
-static int matches_tags_and(UcxList *dav_tags, UcxList *tags, int ignorecase) {
-    UCX_FOREACH(e, tags) {
-        if (!ucx_list_contains(dav_tags, e->data,
-                (cmp_func) compare_tagname, &ignorecase)) {
-            return 0;
+static int matches_tags_and(CxList *dav_tags, CxList *tags, int ignorecase) {
+    // ignorecase not supported yet
+    int ret = 1;
+    CxMap *tagmap = taglist2map(dav_tags);
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag *, tag, i) {
+        if (cxMapGet(tagmap, cx_hash_key_str(tag->name))) {
+            ret = 0;
+            break;
         }
     }
-    return 1;
+    cxMapDestroy(tagmap);
+    return ret;
 }
 
-static int matches_tags_or(UcxList *dav_tags, UcxList *tags, int ignorecase) {
-    UCX_FOREACH(e, tags) {
-        if (ucx_list_contains(dav_tags, e->data,
-                (cmp_func) compare_tagname, &ignorecase)) {
-            return 1;
+static int matches_tags_or(CxList *dav_tags, CxList *tags, int ignorecase) {
+    // ignorecase not supported yet
+    int ret = 0;
+    CxMap *tagmap = taglist2map(dav_tags);
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag *, tag, i) {
+        if (cxMapGet(tagmap, cx_hash_key_str(tag->name))) {
+            ret = 1;
+            break;
         }
     }
-    return 0;
+    cxMapDestroy(tagmap);
+    return ret;
 }
 
-static int matches_tags_one(UcxList *dav_tags, UcxList *tags, int ignorecase) {
+static int matches_tags_one(CxList *dav_tags, CxList *tags, int ignorecase) {
     int matches_exactly_one = 0;
-    UCX_FOREACH(e, tags) {
-        if (ucx_list_contains(dav_tags, e->data,
-                (cmp_func) compare_tagname, &ignorecase)) {
+    CxMap *tagmap = taglist2map(dav_tags);
+    CxIterator i = cxListIterator(tags);
+    cx_foreach(DavTag *, tag, i) {
+        if (cxMapGet(tagmap, cx_hash_key_str(tag->name))) {
             if (matches_exactly_one) {
+                cxMapDestroy(tagmap);
                 return 0;
             } else {
                 matches_exactly_one = 1;
             }
         }
     }
+    cxMapDestroy(tagmap);
     return matches_exactly_one;
 }
 
-static int matches_subfilters_and(UcxList *dav_tags, SyncTagFilter *filter) {
+static int matches_subfilters_and(CxList *dav_tags, SyncTagFilter *filter) {
     int ret = 1;
     for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
         ret &= matches_tagfilter(dav_tags, filter->subfilters[i]);
@@ -682,7 +700,7 @@
     return ret;
 }
 
-static int matches_subfilters_or(UcxList *dav_tags, SyncTagFilter *filter) {
+static int matches_subfilters_or(CxList *dav_tags, SyncTagFilter *filter) {
     int ret = 0;
     for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
         ret |= matches_tagfilter(dav_tags, filter->subfilters[i]);
@@ -690,7 +708,7 @@
     return ret;
 }
 
-static int matches_subfilters_one(UcxList *dav_tags, SyncTagFilter *filter) {
+static int matches_subfilters_one(CxList *dav_tags, SyncTagFilter *filter) {
     int one = 0;
     for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
         if (matches_tagfilter(dav_tags, filter->subfilters[i])) {
@@ -704,7 +722,7 @@
     return one;
 }
 
-int matches_tagfilter(UcxList *dav_tags, SyncTagFilter *tagfilter) {
+int matches_tagfilter(CxList *dav_tags, SyncTagFilter *tagfilter) {
 
     if (tagfilter->subfilter_count > 0) {
         switch (tagfilter->mode) {

mercurial