--- 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) {