libidav/utils.c

changeset 747
efbd59642577
parent 741
e9a5dd08258d
child 757
7ced4052e8ca
--- a/libidav/utils.c	Sun Apr 16 14:12:24 2023 +0200
+++ b/libidav/utils.c	Fri Apr 21 21:25:32 2023 +0200
@@ -32,9 +32,10 @@
 #include <string.h>
 #include <errno.h>
 #include <ctype.h>
-#include <ucx/string.h>
-#include <ucx/buffer.h>
-#include <ucx/utils.h>
+#include <cx/string.h>
+#include <cx/buffer.h>
+#include <cx/utils.h>
+#include <cx/printf.h>
 #include <libxml/tree.h>
 #include <curl/curl.h>
 
@@ -66,7 +67,7 @@
 #include <openssl/rand.h>
 */
 
-static size_t extractval(sstr_t str, char *result, char delim) {
+static size_t extractval(cxstring str, char *result, char delim) {
     size_t n = 0;
     for(size_t i = 0; i < str.length ; i++) {
         if(isdigit(str.ptr[i])) {
@@ -93,19 +94,19 @@
     char conv[16];
     
     // work on the trimmed string
-    sstr_t date = sstrtrim(sstr(iso8601str));
+    cxstring date = cx_strtrim(cx_str(iso8601str));
 
-    sstr_t time = sstrchr(date, 'T');
+    cxstring time = cx_strchr(date, 'T');
     if(time.length == 0) {
         return 0;
     }
     date.length = time.ptr - date.ptr;
     time.ptr++; time.length--;
     
-    sstr_t tzinfo;
-    if((tzinfo = sstrchr(time, 'Z')).length > 0 ||
-        (tzinfo = sstrchr(time, '+')).length > 0 ||
-        (tzinfo = sstrchr(time, '-')).length > 0) {
+    cxstring tzinfo;
+    if((tzinfo = cx_strchr(time, 'Z')).length > 0 ||
+        (tzinfo = cx_strchr(time, '+')).length > 0 ||
+        (tzinfo = cx_strchr(time, '-')).length > 0) {
         
         time.length = tzinfo.ptr - time.ptr;
     }
@@ -124,9 +125,9 @@
     tparts.tm_year = val / 10000 - 1900;
     
     // parse time and skip possible fractional seconds
-    sstr_t frac;
-    if((frac = sstrchr(time, '.')).length > 0 ||
-        (frac = sstrchr(time, ',')).length > 0) {
+    cxstring frac;
+    if((frac = cx_strchr(time, '.')).length > 0 ||
+        (frac = cx_strchr(time, ',')).length > 0) {
         time.length = frac.ptr - time.ptr;
     }
     if((time.length != 6 && time.length != 8)
@@ -144,7 +145,7 @@
         // local time
         tparts.tm_isdst = -1;
         return mktime(&tparts);
-    } else if(!sstrcmp(tzinfo, S("Z"))) {
+    } else if(!cx_strcmp(tzinfo, cx_str("Z"))) {
 #ifdef __FreeBSD__
         return timegm(&tparts);
 #else
@@ -276,13 +277,13 @@
     }
 }
 
-char* util_url_base_s(sstr_t url) {
+char* util_url_base_s(cxstring url) {
     size_t i = 0;
     if(url.length > 0) {
         int slmax;
-        if(sstrprefix(url, SC("http://"))) {
+        if(cx_strprefix(url, cx_str("http://"))) {
             slmax = 3;
-        } else if(sstrprefix(url, SC("https://"))) {
+        } else if(cx_strprefix(url, cx_str("https://"))) {
             slmax = 3;
         } else {
             slmax = 1;
@@ -298,16 +299,16 @@
             }
         }
     }
-    sstr_t server = sstrsubsl(url, 0, i);
-    return sstrdup(server).ptr;
+    cxstring server = cx_strsubsl(url, 0, i);
+    return cx_strdup(server).ptr;
 }
 
 char* util_url_base(char *url) {
-    return util_url_base_s(sstr(url));
+    return util_url_base_s(cx_str(url));
 }
 
-char* util_url_path(char *url) {
-    char *path = NULL;
+const char* util_url_path(const char *url) {
+    const char *path = NULL;
     size_t len = strlen(url);
     int slashcount = 0;
     int slmax;
@@ -335,7 +336,7 @@
     return path;
 }
 
-char* util_url_decode(DavSession *sn, char *url) {
+char* util_url_decode(DavSession *sn, const char *url) {
     char *unesc = curl_easy_unescape(sn->handle, url, strlen(url), NULL);
     char *ret = strdup(unesc);
     curl_free(unesc);
@@ -345,24 +346,24 @@
 static size_t util_header_callback(char *buffer, size_t size,
         size_t nitems, void *data) {
     
-    sstr_t sbuffer = sstrn(buffer, size*nitems);
+    cxstring sbuffer = cx_strn(buffer, size*nitems);
     
-    UcxMap *map = (UcxMap*) data;
+    CxMap *map = (CxMap*) data;
     
     // if we get a status line, clear the map and exit
-    if(sstrprefix(sbuffer, S("HTTP/"))) {
-        ucx_map_free_content(map, free);
-        ucx_map_clear(map);
+    if(cx_strprefix(sbuffer, cx_str("HTTP/"))) {
+        // TODO: use new map destructor   ucx_map_free_content(map, free);
+        cxMapClear(map);
         return size*nitems;
     }
     
     // if we get the terminating CRLF, just exit
-    if(!sstrcmp(sbuffer, S("\r\n"))) {
+    if(!cx_strcmp(sbuffer, cx_str("\r\n"))) {
         return 2;
     }
     
-    sstr_t key = sbuffer;
-    sstr_t value = sstrchr(sbuffer, ':');
+    cxstring key = sbuffer;
+    cxstring value = cx_strchr(sbuffer, ':');
     
     if(value.length == 0) {
         return 0; // invalid header line
@@ -371,19 +372,20 @@
     key.length = value.ptr - key.ptr;
     value.ptr++; value.length--;
     
-    key = sstrlower(sstrtrim(key));
-    value = sstrdup(sstrtrim(value));
+    cxmutstr key_cp = cx_strdup(cx_strtrim(key));
+    cx_strlower(key_cp);
+    cxmutstr value_cp = cx_strdup(cx_strtrim(value));
         
-    ucx_map_sstr_put(map, key, value.ptr);
+    cxMapPut(map, cx_hash_key(key_cp.ptr, key_cp.length), value_cp.ptr);
     
-    free(key.ptr);
+    free(key_cp.ptr);
     
     return sbuffer.length;
 }
 
 int util_path_isrelated(const char *path1, const char *path2) {
-    scstr_t p1 = scstr(path1);
-    scstr_t p2 = scstr(path2);
+    cxstring p1 = cx_str(path1);
+    cxstring p2 = cx_str(path2);
     
     if(IS_PATH_SEPARATOR(p1.ptr[p1.length-1])) {
         p1.length--;
@@ -396,11 +398,11 @@
         return 0;
     }
     
-    if(!sstrcmp(p1, p2)) {
+    if(!cx_strcmp(p1, p2)) {
         return 1;
     }
     
-    if(sstrprefix(p2, p1)) {
+    if(cx_strprefix(p2, p1)) {
         if(IS_PATH_SEPARATOR(p2.ptr[p1.length])) {
             return 1;
         }
@@ -434,10 +436,11 @@
 
 char* util_path_normalize(const char *path) {
     size_t len = strlen(path);
-    UcxBuffer *buf = ucx_buffer_new(NULL, len+1, UCX_BUFFER_AUTOEXTEND);
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, len+1, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     
     if(path[0] == '/') {
-        ucx_buffer_putc(buf, '/');
+        cxBufferPut(&buf, '/');
     }
     
     int add_separator = 0;
@@ -453,25 +456,25 @@
             }
             
             if(seg_len > 0) {
-                scstr_t seg = scstrn(seg_ptr, seg_len);
-                if(!sstrcmp(seg, SC(".."))) {
-                    for(int j=buf->pos;j>=0;j--) {
-                        char t = buf->space[j];
+                cxstring seg = cx_strn(seg_ptr, seg_len);
+                if(!cx_strcmp(seg, CX_STR(".."))) {
+                    for(int j=buf.pos;j>=0;j--) {
+                        char t = buf.space[j];
                         if(IS_PATH_SEPARATOR(t) || j == 0) {
-                            buf->pos = j;
-                            buf->size = j;
-                            buf->space[j] = 0;
+                            buf.pos = j;
+                            buf.size = j;
+                            buf.space[j] = 0;
                             add_separator = IS_PATH_SEPARATOR(t) ? 1 : 0;
                             break;
                         }
                     }
-                } else if(!sstrcmp(seg, SC("."))) {
+                } else if(!cx_strcmp(seg, CX_STR("."))) {
                     // ignore
                 } else {
                     if(add_separator) {
-                        ucx_buffer_putc(buf, PATH_SEPARATOR);
+                        cxBufferPut(&buf, PATH_SEPARATOR);
                     }
-                    ucx_buffer_write(seg_ptr, 1, seg_len, buf);
+                    cxBufferWrite(seg_ptr, 1, seg_len, &buf);
                     add_separator = 1;
                 }
             }
@@ -480,13 +483,9 @@
         }
     }
     
-    ucx_buffer_putc(buf, 0);
-    
+    cxBufferPut(&buf, 0);
     
-    char *space = buf->space;
-    buf->flags = 0; // disable autofree
-    ucx_buffer_free(buf);
-    return space;
+    return buf.space;
 }
 
 static char* create_relative_path(const char *abspath, const char *base) {
@@ -523,7 +522,7 @@
     }
     
     char *ret = NULL;
-    UcxBuffer *out = NULL;
+    CxBuffer out;
     if(last_dir+1 < base_len) {
         // base is deeper than the link root, we have to go backwards
         int dircount = 0;
@@ -533,22 +532,19 @@
             }
         }
         
-        out = ucx_buffer_new(NULL, dircount*3+path_len-last_dir, UCX_BUFFER_AUTOEXTEND);
+        cxBufferInit(&out, NULL, dircount*3+path_len-last_dir, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
         
         for(int i=0;i<dircount;i++) {
-            ucx_buffer_puts(out, "../");
+            cxBufferPutString(&out, "../");
         }
     } else {
-        out = ucx_buffer_new(NULL, 1024, path_len - last_dir);
+        cxBufferInit(&out, NULL, path_len - last_dir, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     }
     
-    ucx_buffer_puts(out, abspath + last_dir + 1);
-    ucx_buffer_putc(out, 0);
-    out->flags = 0;
-    ret = out->space;
-    ucx_buffer_free(out);
+    cxBufferPutString(&out, abspath + last_dir + 1);
+    cxBufferPut(&out, 0);
     
-    return ret;
+    return out.space;
 }
 
 #ifdef _WIN32
@@ -581,7 +577,7 @@
 #endif
 
 
-void util_capture_header(CURL *handle, UcxMap* map) {
+void util_capture_header(CURL *handle, CxMap* map) {
     if(map) {
         curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, util_header_callback);
         curl_easy_setopt(handle, CURLOPT_HEADERDATA, map);
@@ -591,12 +587,12 @@
     }
 }
 
-char* util_resource_name(char *url) {
-    sstr_t urlstr = sstr(url);
+const char* util_resource_name(const char *url) {
+    cxstring urlstr = cx_str(url);
     if(urlstr.ptr[urlstr.length-1] == '/') {
         urlstr.length--;
     }
-    sstr_t resname = sstrrchr(urlstr, '/');
+    cxstring resname = cx_strrchr(urlstr, '/');
     if(resname.length > 1) {
         return resname.ptr+1;
     } else {
@@ -613,12 +609,12 @@
 }
 
 char* util_concat_path(const char *url_base, const char *p) {
-    sstr_t base = sstr((char*)url_base);
-    sstr_t path;
+    cxstring base = cx_str((char*)url_base);
+    cxstring path;
     if(p) {
-        path = sstr((char*)p);
+        path = cx_str((char*)p);
     } else {
-        path = sstrn("", 0);
+        path = CX_STR("");
     }
     
     int add_separator = 0;
@@ -632,24 +628,24 @@
         }
     }
     
-    sstr_t url;
+    cxmutstr url;
     if(add_separator) {
-        url = sstrcat(3, base, sstr("/"), path);
+        url = cx_strcat(3, base, CX_STR("/"), path);
     } else {
-        url = sstrcat(2, base, path);
+        url = cx_strcat(2, base, path);
     }
     
     return url.ptr;
 }
 
 char* util_get_url(DavSession *sn, const char *href) {
-    scstr_t base = scstr(sn->base_url);
-    scstr_t href_str = scstr(href);
+    cxstring base = cx_str(sn->base_url);
+    cxstring href_str = cx_str(href);
     
-    char *base_path = util_url_path(sn->base_url);
+    const char *base_path = util_url_path(sn->base_url);
     base.length -= strlen(base_path);
     
-    sstr_t url = sstrcat(2, base, href_str);
+    cxmutstr url = cx_strcat(2, base, href_str);
     return url.ptr;
 }
 
@@ -659,43 +655,38 @@
     free(url);
 }
 
-char* util_path_to_url(DavSession *sn, char *path) {
-    char *space = malloc(256);
-    UcxBuffer *url = ucx_buffer_new(space, 256, UCX_BUFFER_AUTOEXTEND);
+char* util_path_to_url(DavSession *sn, const char *path) {
+    CxBuffer url;
+    cxBufferInit(&url, NULL, 256, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     
     // add base url
-    ucx_buffer_write(sn->base_url, 1, strlen(sn->base_url), url);
+    cxBufferWrite(sn->base_url, 1, strlen(sn->base_url), &url);
     // remove trailing slash
-    ucx_buffer_seek(url, -1, SEEK_CUR);
+    cxBufferSeek(&url, -1, SEEK_CUR);
     
-    sstr_t p = sstr(path);
-    ssize_t ntk = 0;
-    sstr_t *tks = sstrsplit(p, S("/"), &ntk);
+    cxstring p = cx_str(path);
     
-    for(int i=0;i<ntk;i++) {
-        sstr_t node = tks[i];
+    CxStrtokCtx tkctx = cx_strtok(p, CX_STR("/"), INT_MAX);
+    cxstring node;
+    while(cx_strtok_next(&tkctx, &node)) {
         if(node.length > 0) {
             char *esc = curl_easy_escape(sn->handle, node.ptr, node.length);
-            ucx_buffer_putc(url, '/');
-            ucx_buffer_write(esc, 1, strlen(esc), url);
+            cxBufferPut(&url, '/');
+            cxBufferWrite(esc, 1, strlen(esc), &url);
             curl_free(esc);
         }
-        free(node.ptr);
-    }
-    free(tks);
-    if(path[p.length-1] == '/') {
-        ucx_buffer_putc(url, '/');
     }
-    ucx_buffer_putc(url, 0);
     
-    space = url->space;
-    ucx_buffer_free(url);
+    if(path[p.length-1] == '/') {
+        cxBufferPut(&url, '/');
+    }
+    cxBufferPut(&url, 0);
     
-    return space;
+    return url.space;
 }
 
 char* util_parent_path(const char *path) {
-    char *name = util_resource_name((char*)path);
+    const char *name = util_resource_name(path);
     size_t namelen = strlen(name);
     size_t pathlen = strlen(path);
     size_t parentlen = pathlen - namelen;
@@ -952,11 +943,11 @@
     return out;
 }
 
-char* util_encrypt_str(DavSession *sn, char *str, char *key) {
+char* util_encrypt_str(DavSession *sn, const char *str, const char *key) {
     DavKey *k = dav_context_get_key(sn->context, key);
     if(!k) {
         sn->error = DAV_ERROR;
-        sstr_t err = ucx_sprintf("Key %s not found", key);
+        cxmutstr err = cx_asprintf("Key %s not found", key);
         dav_session_set_errstr(sn, err.ptr);
         free(err.ptr);
         return NULL;
@@ -965,18 +956,18 @@
     return util_encrypt_str_k(sn, str, k);
 }
 
-char* util_encrypt_str_k(DavSession *sn, char *str, DavKey *key) {
+char* util_encrypt_str_k(DavSession *sn, const char *str, DavKey *key) {
     char *enc_str = aes_encrypt(str, strlen(str), key);
     char *ret_str = dav_session_strdup(sn, enc_str);
     free(enc_str);
     return ret_str;
 }
 
-char* util_decrypt_str(DavSession *sn, char *str, char *key) {
+char* util_decrypt_str(DavSession *sn, const char *str, const char *key) {
     DavKey *k = dav_context_get_key(sn->context, key);
     if(!k) {
         sn->error = DAV_ERROR;
-        sstr_t err = ucx_sprintf("Key %s not found", key);
+        cxmutstr err = cx_asprintf("Key %s not found", key);
         dav_session_set_errstr(sn, err.ptr);
         free(err.ptr);
         return NULL;
@@ -985,7 +976,7 @@
     return util_decrypt_str_k(sn, str, k);
 }
 
-char* util_decrypt_str_k(DavSession *sn, char *str, DavKey *key) {
+char* util_decrypt_str_k(DavSession *sn, const char *str, DavKey *key) {
     size_t len = 0;
     char *dec_str = aes_decrypt(str, &len, key);
     char *ret_str = dav_session_strdup(sn, dec_str);
@@ -997,7 +988,7 @@
     unsigned char *str = malloc(25);
     str[24] = '\0';
     
-    sstr_t t = S(
+    cxstring t = CX_STR(
             "01234567890"
             "abcdefghijklmnopqrstuvwxyz"
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -1021,6 +1012,8 @@
  * tokens are separated by space
  * sets sub to the substring and returns the remaining string
  */
+// TODO: remove if it isn't used
+/*
 sstr_t util_getsubstr_until_token(sstr_t str, sstr_t token, sstr_t *sub) {  
     int i;
     int token_start = -1;
@@ -1060,20 +1053,22 @@
         return str;
     }
 }
+*/
 
-sstr_t util_readline(FILE *stream) {
-    UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
+cxmutstr util_readline(FILE *stream) {
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     
     int c;
     while((c = fgetc(stream)) != EOF) {
         if(c == '\n') {
             break;
         }
-        ucx_buffer_putc(buf, c);
+        cxBufferPut(&buf, c);
     }
     
-    sstr_t str = sstrdup(sstrtrim(sstrn(buf->space, buf->size)));
-    ucx_buffer_free(buf);
+    cxmutstr str = cx_strdup(cx_strtrim(cx_strn(buf.space, buf.size)));
+    cxBufferDestroy(&buf);
     return str;
 }
 
@@ -1097,15 +1092,16 @@
 #endif
     
     // read password input
-    UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     int c = 0;
     while((c = getpasswordchar()) != EOF) {
         if(c == '\n' || c == '\r') {
             break;
         }
-        ucx_buffer_putc(buf, c);
+        cxBufferPut(&buf, c);
     }
-    ucx_buffer_putc(buf, 0);
+    cxBufferPut(&buf, 0);
     fflush(stdin);
     
 #ifndef _WIN32
@@ -1115,12 +1111,10 @@
     }
 #endif
     
-    char *str = buf->space;
-    free(buf); // only free the UcxBuffer struct
-    return str;
+    return buf.space;
 }
 
-int util_exec_command(char *command, UcxBuffer *outbuf) {
+int util_exec_command(char *command, CxBuffer *outbuf) {
 #ifdef _WIN32
     fprintf(stderr, "util_exec_command unsupported\n");
     return 1;
@@ -1156,7 +1150,7 @@
         ssize_t r;
         char buf[1024];
         while((r = read(pout[0], buf, 1024)) > 0) {
-            ucx_buffer_write(buf, 1, r, outbuf);
+            cxBufferWrite(buf, 1, r, outbuf);
         }
     }
     
@@ -1173,14 +1167,13 @@
 
 char* util_hexstr(const unsigned char *data, size_t len) {
     size_t buflen = 2*len + 4;
-    UcxBuffer *buf = ucx_buffer_new(malloc(buflen), buflen + 1, 0);
+    CxBuffer buf;
+    cxBufferInit(&buf, NULL, buflen + 1, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
     for(int i=0;i<len;i++) {
-        ucx_bprintf(buf, "%02x", data[i]);
+        cx_bprintf(&buf, "%02x", data[i]);
     }
-    ucx_buffer_putc(buf, 0);
-    char *str = buf->space;
-    ucx_buffer_free(buf);
-    return str;
+    cxBufferPut(&buf, 0);
+    return buf.space;
 }
 
 void util_remove_trailing_pathseparator(char *path) {
@@ -1215,3 +1208,25 @@
     
     return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);    
 }
+
+struct regdestructor {
+    cx_destructor_func destructor;
+    void *data;
+};
+
+static void call_destructor(struct regdestructor *d) {
+    d->destructor(d->data);
+}
+
+int util_regdestr(CxMempool *mp, void *data, cx_destructor_func destructor) {
+    // the ucx maintainer doesn't like me anymore and forces me to 
+    // implement basic stuff by myself
+    struct regdestructor *reg = cxMalloc(mp->allocator, sizeof(struct regdestructor));
+    if(!reg) {
+        return 1;
+    }
+    reg->destructor = destructor;
+    reg->data = data;
+    cxMempoolSetDestructor(mp, reg, (cx_destructor_func)call_destructor);
+    return 0;
+}

mercurial