skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

bigkv_fill.c (1893B)


      1 /* ISC license. */
      2 
      3 #include <stdint.h>
      4 #include <string.h>
      5 #include <errno.h>
      6 
      7 #include <skalibs/bytestr.h>
      8 #include <skalibs/stralloc.h>
      9 #include <skalibs/genalloc.h>
     10 #include <skalibs/avltree.h>
     11 #include <skalibs/bigkv.h>
     12 
     13 static void *bigkv_dtok (uint32_t d, void *p)
     14 {
     15   bigkv *b = p ;
     16   return b->storage.s + genalloc_s(bigkv_node, &b->nodes)[d].k ;
     17 }
     18 
     19 static int bigkv_cmp (void const *a, void const *b, void *p)
     20 {
     21   (void)p ;
     22   return strcmp((char const *)a, (char const *)b) ;
     23 }
     24 
     25 int bigkv_fill (bigkv *b, char const *const *argv, char delim, char const *prefix, char const *stop, uint32_t options)
     26 {
     27   int i = 0 ;
     28   size_t prefixlen = prefix ? strlen(prefix) : 0 ;
     29   avltree_init(&b->map, 3, 3, 8, &bigkv_dtok, &bigkv_cmp, b) ;
     30   for (; argv[i] && !(stop && !strcmp(argv[i], stop)) ; i++)
     31   {
     32     bigkv_node node = { .k = b->storage.len } ;
     33     char const *s = argv[i] ;
     34     size_t len = strlen(s) ;
     35     size_t pos ;
     36     int isdup ;
     37     uint32_t d ;
     38     if (prefixlen)
     39     {
     40       if (!strncmp(s, prefix, prefixlen)) return i+1 ;
     41       s += prefixlen ;
     42       len -= prefixlen ;
     43     }
     44     pos = byte_chr(s, len, delim) ;
     45     if (!stralloc_catb(&b->storage, s, pos+1)) goto err ;
     46     b->storage.s[pos] = 0 ;
     47     isdup = avltree_search(&b->map, s, &d) ;
     48     if (isdup)
     49     {
     50       if (options & BIGKV_OPTIONS_NODUP) goto invalid ;
     51       b->storage.len = node.k ;
     52     }
     53     if (pos < len)
     54     {
     55       node.v = b->storage.len ;
     56       if (!stralloc_catb(&b->storage, s + pos + 1, len - pos)) goto err ;
     57     }
     58     else node.v = b->storage.len - 1 ;
     59     if (isdup) genalloc_s(bigkv_node, &b->nodes)[d].v = node.v ;
     60     else
     61     {
     62       d = genalloc_len(bigkv_node, &b->nodes) ;
     63       if (!genalloc_append(bigkv_node, &b->nodes, &node)) goto err ;
     64       if (!avltree_insert(&b->map, d)) goto err ;
     65     }
     66   }
     67   return i ;
     68 
     69  invalid:
     70    errno = EINVAL ;
     71  err:
     72   bigkv_free(b) ;
     73   return -1 ;
     74 }