libsheepy

C lib for handling text files, strings and json like data structure with an object oriented system
git clone https://spartatek.se/git/libsheepy.git
Log | Files | Refs | README | LICENSE

libsheepyBt.c (29640B)


      1 #include "libsheepyBt.h"
      2 
      3 #ifndef LIBSHEEPY_VERSION
      4 #define libsheepyPrealloc (1024*1024)
      5 #define makeRoom(length, alloc, addlength) funcbegin\
      6     typeof(alloc) r;\
      7     typeof(alloc) newlen = (length) + (addlength);\
      8     if (newlen < (alloc)) {\
      9       r = alloc;\
     10     } \
     11     else {\
     12       if (newlen < libsheepyPrealloc) {\
     13         r = newlen * 2;\
     14       }\
     15       else {\
     16         r = newlen + libsheepyPrealloc;\
     17       }\
     18     }\
     19     r;\
     20   funcend
     21 #endif
     22 
     23 /**
     24  * return a btt object with s as buffer
     25  */
     26 btt initCharB(char *s) {
     27   ret charB(s);
     28 }
     29 
     30 /**
     31  * return a btt object with s as buffer
     32  * the buffer is not going to be reallocated
     33  */
     34 btt initCCharB(char *s) {
     35   ret ccharB(s);
     36 }
     37 
     38 /**
     39  * return a btt object with buf as buffer
     40  */
     41 btt initB(void *buf, u32 len, bool allocated) {
     42   ret voidB(buf, len, allocated);
     43 }
     44 
     45 /**
     46  * return a btt object with a heap allocated buffer of size allocateSize
     47  */
     48 btt newB(u32 allocateSize) {
     49   btt r    = {.len = 0};
     50   r.b     = malloc(allocateSize ? allocateSize : 4/*allocate 4 bytes when len is 0*/);
     51   if (!r.b) ret emptybt;
     52   r.alloc = allocateSize;
     53   ret r;
     54 }
     55 
     56 /**
     57  * return a heap allocated btt object with a heap allocated buffer of size allocateSize
     58  */
     59 btt *allocNewB(u32 allocateSize) {
     60   btt *r = malloc(sizeof(*r));
     61   *r    = newB(allocateSize ? allocateSize : 4/*allocate 4 bytes when len is 0*/);
     62   ret r;
     63 }
     64 
     65 bool reallocB(btt *b, size_t newSize) {
     66   if (!b or (/*read only*/b->alloc == 0 and b->len > 0) or newSize == 0/*==0 will free the b->b buffer*/) ret false;
     67   u8 *tmp = realloc(b->b, newSize);
     68   if (!tmp) ret false; /*realloc failed*/
     69   b->b     = tmp;
     70   b->alloc = newSize;
     71   // when newSize is shorter than the buffer length
     72   // truncate the buffer
     73   if (newSize < b->len) b->len = newSize;
     74   ret true;
     75 }
     76 
     77 // not needed, use charB or ccharB
     78 // /**
     79 //  * set buf in the b btt object
     80 //  */
     81 // btt *setB(btt *b, char *buf, bool allocated) {
     82 //   if (!b or !buf) ret null;
     83 //   b->b     = buf;
     84 //   b->len   = strlen(buf);
     85 //   b->alloc = (allocated) ? b->len : 0;
     86 //   ret b;
     87 // }
     88 
     89 /**
     90  * return a heap allocated btt object with buf assigned to it
     91  */
     92 btt *allocCharB(char *buf) {
     93   if (!buf) ret null;
     94   btt *r = malloc(sizeof(*r));
     95   if (!r) ret null;
     96   *r    = charB(buf);
     97   ret r;
     98 }
     99 
    100 /**
    101  * return a heap allocated btt object with buf assigned to it
    102  */
    103 btt *allocCCharB(char *buf) {
    104   if (!buf) ret null;
    105   btt *r = malloc(sizeof(*r));
    106   if (!r) ret null;
    107   *r    = ccharB(buf);
    108   ret r;
    109 }
    110 
    111 btt *allocBufB(void *buf, u32 len, bool allocated) {
    112   if (!buf) ret null;
    113   btt *r = malloc(sizeof(*r));
    114   if (!r) ret null;
    115   *r    = voidB(buf, len, allocated);
    116   ret r;
    117 }
    118 
    119 /**
    120  * return a heap allocated btt object with b assigned to it
    121  */
    122 btt *allocB(const btt b) {
    123   btt *r = malloc(sizeof(*r));
    124   if (!r) ret null;
    125   *r    = b;
    126   ret r;
    127 }
    128 
    129 /**
    130  * return a heap allocated btt object with *b assigned to it
    131  */
    132 btt *allocPB(const btt *b) {
    133   if (!b) ret null;
    134   ret allocB(*b);
    135 }
    136 
    137 /**
    138  * return a btt object with a heap allocated copy of b.b
    139  */
    140 btt copyB(const btt b) {
    141   btt r   = b;
    142   r.alloc = b.len ? b.len : 4 /*allocate 4 bytes when len is 0*/;
    143   r.b     = malloc(r.alloc);
    144   memcpy(r.b, b.b, b.len);
    145   ret r;
    146 }
    147 
    148 btt copyPB(btt *b) {
    149   if (!b) ret emptybt;
    150   ret copyB(*b);
    151 }
    152 
    153 /**
    154  * return a heap allocated btt object with a heap allocated copy of b.b
    155  */
    156 btt *dupB(const btt b) {
    157   btt *r = malloc(sizeof(*r));
    158   *r    = copyB(b);
    159   ret r;
    160 }
    161 
    162 btt *dupPB(btt *b) {
    163   if (!b) ret null;
    164   ret dupB(*b);
    165 }
    166 
    167 btt *setValB(btt *b, btt *a) {
    168   if (!a or !b) ret null;
    169   freenB(b);
    170   *b = *a;
    171   ret b;
    172 }
    173 
    174 /**
    175  * free heap allocated .b
    176  * nothing if not heap allocated
    177  */
    178 void freeB(btt b) {
    179   if (b.alloc) {
    180     free(b.b);
    181   }
    182 }
    183 
    184 /**
    185  * free heap allocated .b and assign null to .b
    186  * nothing if not heap allocated
    187  */
    188 void freenB(btt *b) {
    189   if (b and b->alloc) {
    190     freen(b->b);
    191     b->len = 0;
    192     b->alloc = 0;
    193   }
    194 }
    195 
    196 /**
    197  * free the heap allocated btt object (container only, not .b)
    198  */
    199 void finishB(btt **b) {
    200   if (b) {
    201     free(*b);
    202     *b = null;
    203   }
    204 }
    205 
    206 /**
    207  * free the heap allocated btt object and free .b
    208  */
    209 void terminateB(btt **b) {
    210   if (b) {
    211     if (*b and (*b)->alloc) {
    212       free((*b)->b);
    213     }
    214     free(*b);
    215     *b = null;
    216   }
    217 }
    218 
    219 // terminate val when it is out of scope
    220 void cleanUpTerminateB(btt **val) {
    221   terminateB(val);
    222 }
    223 
    224 // free local val when it is out of scope
    225 void cleanUpFreeLocalB(btt *val) {
    226   freeB(*val);
    227 }
    228 
    229 // free val when it is out of scope
    230 void cleanUpFreeB(btt **val) {
    231   freeB(**val);
    232 }
    233 
    234 // finish val when it is out of scope
    235 void cleanUpFinishB(btt **val) {
    236   finishB(val);
    237 }
    238 
    239 // convert btt to char* allocated on heap
    240 char *toCharB(btt *b) {
    241   if (not b or not b->b) ret null;
    242   char *r = malloc(b->len+1);
    243   if (not r) ret null;
    244   if (b->len) memcpy(r, b->b, b->len);
    245   r[b->len] = 0;
    246   ret r;
    247 }
    248 
    249 bool isEmptyB(const btt b) {
    250   if (not b.b or not b.len) ret yes;
    251   ret no;
    252 }
    253 
    254 bool isEmptyPB(btt *b) {
    255   if (not b) ret yes;
    256   ret isEmptyB(*b);
    257 }
    258 
    259 bool isValidB(const btt b) {
    260   if (not b.b or (b.alloc and b.len > b.alloc)) ret no;
    261   ret yes;
    262 }
    263 
    264 bool isValidPB(btt *b) {
    265   if (not b) ret no;
    266   ret isValidB(*b);
    267 }
    268 
    269 bool eqCharB(btt a, char *b) {
    270   if (not b or not a.b) ret no;
    271   if (a.len != strlen(b)) ret no;
    272   ret memcmp(a.b, b, a.len) == 0;
    273 }
    274 
    275 /**
    276  * return a btt object with s appended to b
    277  * b doesn't need to have a heap allocated buffer
    278  */
    279 btt pushB(const btt b, const char *s) {
    280   // duplicate b.b
    281   // copy s to b end
    282   btt r  = copyB(b);
    283   btt *p = bPushB(&r, s);
    284   if (p) ret r;
    285   else {
    286     freeB(r);
    287     ret emptybt;
    288   }
    289 }
    290 
    291 // TODO pushManyB
    292 
    293 /**
    294  * update b and append s
    295  * b.b is reallocated
    296  */
    297 btt *bPushB(btt *b, const char *s) {
    298   if (!b or !b->b or !s) ret null;
    299 
    300   size_t len = strlen(s);
    301   u32 newsize = makeRoom(b->len, b->alloc, len);
    302   // check if there is enough space
    303   if (newsize > b->alloc) {
    304     u8 *tmp = realloc(b->b, newsize);
    305     if (!tmp) ret null;
    306     b->b = tmp;
    307     b->alloc = newsize;
    308   }
    309   // copy s to b end
    310   memcpy(b->b+b->len, s, len);
    311   b->len += len;
    312   ret b;
    313 }
    314 
    315 /**
    316  * update b and append '\0'
    317  * b.b is reallocated
    318  */
    319 btt *bPushNulB(btt *b) {
    320   if (!b or !b->b) ret null;
    321 
    322   u32 newsize = makeRoom(b->len, b->alloc, 1);
    323   // check if there is enough space
    324   if (newsize > b->alloc) {
    325     u8 *tmp = realloc(b->b, newsize);
    326     if (!tmp) ret null;
    327     b->b = tmp;
    328     b->alloc = newsize;
    329   }
    330   b->b[b->len] = 0;
    331   b->len++;
    332   ret b;
    333 }
    334 
    335 // TODO bPushManyB
    336 
    337 /**
    338  * return a btt object with s btt object appended to b
    339  * b doesn't need to have a heap allocated buffer
    340  */
    341 btt pushBB(const btt b, const btt s) {
    342   // duplicate b.b
    343   // copy s to b end
    344   btt r  = copyB(b);
    345   btt *p = bPushBB(&r, s);
    346   if (p) ret r;
    347   else {
    348     freeB(r);
    349     ret emptybt;
    350   }
    351   ret r;
    352 }
    353 
    354 // TODO bPushManyBB
    355 
    356 /**
    357  * update b and append s btt object
    358  * b.b is reallocated
    359  */
    360 btt *bPushBB(btt *b, const btt s) {
    361 
    362   if (!b or !b->b or !s.b) ret null;
    363   if (!s.len) ret b;
    364 
    365   u32 newsize = makeRoom(b->len, b->alloc, s.len);
    366   // check if there is enough space
    367   if (newsize > b->alloc) {
    368     u8 *tmp = realloc(b->b, newsize);
    369     if (!tmp) ret null;
    370     b->b = tmp;
    371     b->alloc = newsize;
    372   }
    373   // copy s to b end
    374   memcpy(b->b+b->len, s.b, s.len);
    375   b->len += s.len;
    376   ret b;
    377 }
    378 
    379 // TODO bPushManyBB
    380 
    381 /**
    382  * return a btt object with *s btt object appended to b
    383  * b doesn't need to have a heap allocated buffer
    384  */
    385 btt pushBPB(const btt b, const btt *s) {
    386   if (!s) ret emptybt;
    387   // duplicate b.b
    388   // copy s to b end
    389   ret pushBB(b, *s);
    390 }
    391 
    392 // TODO bPushManyBPB
    393 
    394 /**
    395  * update b and append *s btt object
    396  * b.b is reallocated
    397  */
    398 btt *bPushBPB(btt *b, const btt *s) {
    399   if (!s) ret null;
    400   // copy s to b end
    401   ret bPushBB(b, *s);
    402 }
    403 
    404 // TODO bPushManyBB
    405 
    406 /**
    407  * return a btt object with s appended to *b
    408  * b doesn't need to have a heap allocated buffer
    409  */
    410 btt pushPB(const btt *b, const char *s) {
    411   if (!b) ret emptybt;
    412   ret pushB(*b, s);
    413 }
    414 // TODO pushManyPB...
    415 
    416 /**
    417  * return a btt object with s btt object appended to *b
    418  * b doesn't need to have a heap allocated buffer
    419  */
    420 btt pushPBB(const btt *b, const btt s) {
    421   if (!b) ret emptybt;
    422   ret pushBB(*b, s);
    423 }
    424 // TODO pushManyPBB...
    425 
    426 /**
    427  * return a btt object with *s btt object appended to *b
    428  * b doesn't need to have a heap allocated buffer
    429  */
    430 btt pushPBPB(const btt *b, const btt *s) {
    431   if (!b) ret emptybt;
    432   ret pushBPB(*b, s);
    433 }
    434 // TODO pushManyPBPB...
    435 
    436 /**
    437  * buffer insert string in string at index
    438  *
    439  * return string with toInsert at index
    440  * negative indexes are allowed
    441  * index -1 is the end of the array and is equivalent to index len
    442  *
    443  * \param
    444  *   string
    445  * \param
    446  *   index in string
    447  * \param
    448  *   toInsert string
    449  * \return
    450  *   modified string
    451  *   NULL unchanged string when string is NULL or invalid index
    452  */
    453 btt *bInsertB(btt *b, int64_t index, const char *toInsert) {
    454   if (!b or !b->b or !toInsert) return NULL;
    455   if (b->alloc == 0 and b->len > 0) {
    456     // string is not allocated so it is readonly
    457     return(NULL);
    458   }
    459   int64_t blen = (int64_t)b->len;
    460 
    461   if (!blen && index == -1) {
    462     // empty string, index -1 is equal to 0
    463     index = 0;
    464   }
    465   bool neg = false;
    466   if (index < 0) {
    467     neg = true;
    468   }
    469 
    470   if (index > blen) {
    471     return(NULL);
    472   }
    473   if (neg) {
    474     index++;
    475   }
    476   if (index < -blen) {
    477     return(NULL);
    478   }
    479   if (neg) {
    480     index = blen + index;
    481   }
    482 
    483   size_t len = strlen(toInsert);
    484   u32 newsize = makeRoom(b->len, b->alloc, len);
    485   // check if there is enough space
    486   if (newsize > b->alloc) {
    487     u8 *tmp = realloc(b->b, newsize);
    488     if (!tmp) return NULL;
    489     b->b = tmp;
    490     b->alloc = newsize;
    491   }
    492   // when index == b->len, just add toInsert at the end
    493   if (index < b->len) {
    494     memmove(b->b+index+len, b->b+index, b->len - index);
    495   }
    496   // copy toInsert at index in b
    497   memcpy(b->b+index, toInsert, len);
    498   b->len += len;
    499   return b;
    500 }
    501 
    502 /**
    503  * buffer insert btt string in string at index
    504  *
    505  * return string with toInsert at index
    506  * negative indexes are allowed
    507  * index -1 is the end of the array and is equivalent to index len
    508  *
    509  * \param
    510  *   string
    511  * \param
    512  *   index in string
    513  * \param
    514  *   toInsert string
    515  * \return
    516  *   modified string
    517  *   NULL unchanged string when string is NULL or invalid index
    518  */
    519 btt *bInsertBB(btt *b, int64_t index, const btt *toInsert) {
    520   if (!b or !b->b or !toInsert or !toInsert->b) return NULL;
    521   if (b->alloc == 0 and b->len > 0) {
    522     // string is not allocated so it is readonly
    523     return(NULL);
    524   }
    525   int64_t blen = (int64_t)b->len;
    526 
    527   if (!blen && index == -1) {
    528     // empty string, index -1 is equal to 0
    529     index = 0;
    530   }
    531   bool neg = false;
    532   if (index < 0) {
    533     neg = true;
    534   }
    535 
    536   if (index > blen) {
    537     return(NULL);
    538   }
    539   if (neg) {
    540     index++;
    541   }
    542   if (index < -blen) {
    543     return(NULL);
    544   }
    545   if (neg) {
    546     index = blen + index;
    547   }
    548 
    549   size_t len = toInsert->len;
    550   u32 newsize = makeRoom(b->len, b->alloc, len);
    551   // check if there is enough space
    552   if (newsize > b->alloc) {
    553     u8 *tmp = realloc(b->b, newsize);
    554     if (!tmp) return NULL;
    555     b->b = tmp;
    556     b->alloc = newsize;
    557   }
    558   // when index == b->len, just add toInsert at the end
    559   if (index < b->len) {
    560     memmove(b->b+index+len, b->b+index, b->len - index);
    561   }
    562   // copy toInsert at index in b
    563   memcpy(b->b+index, toInsert->b, len);
    564   b->len += len;
    565   return b;
    566 }
    567 
    568 /**
    569  * buffer delete string
    570  *
    571  * return string without the string between start and end
    572  * negative indexes are allowed
    573  *
    574  * \param
    575  *   string to delete
    576  * \param
    577  *   start: start index, must be in the string
    578  * \param
    579  *   end: end index, must be in the string after start
    580  * \return
    581  *   sliced string
    582  *   unchanged string when start=end
    583  *   NULL when start and end are not set correctly
    584  *        or when input string is NULL or when malloc failed or when end is under start
    585  */
    586 btt *bDelB(btt *string, int64_t start, int64_t end) {
    587   int64_t len;
    588 
    589   // sanity checks
    590   if (!string or !string->b) {
    591     return(NULL);
    592   }
    593   if (string->alloc == 0 and string->len > 0) {
    594     // string is not allocated so it is readonly
    595     return(NULL);
    596   }
    597 
    598   len = (int64_t)string->len;
    599 
    600   if (start >= len) {
    601     start = len;
    602   }
    603   if (end > len) {
    604     end = len;
    605   }
    606   if (start <= -len) {
    607     start = -len;
    608   }
    609   if (end <= -len) {
    610     end = -len;
    611   }
    612   if (start < 0) {
    613     start = len + start;
    614   }
    615   if (end <= 0) {
    616     end = len + end;
    617   }
    618   if (end < start) {
    619     return(NULL);
    620   }
    621 
    622   if (start == end) {
    623     return(string);
    624   }
    625 
    626   // start < end < len
    627   // copy range to a new string
    628   int64_t n;
    629   n = end - start;
    630   memmove(string->b+start, string->b+start+n, (size_t)(len-n-start));
    631   string->len -= n;
    632 
    633   return(string);
    634 }
    635 
    636 /**
    637  * buffer delete element/character string
    638  *
    639  * return string without the character at given index
    640  * negative indexes are allowed
    641  *
    642  * \param
    643  *   string to delete
    644  * \param
    645  *   index: must be in the string, -1 is the last character in the string
    646  * \return
    647  *   string with one less character
    648  *   NULL when input string is NULL or invalid index
    649  */
    650 btt *bDelElemB(btt *string, int64_t index) {
    651   int64_t len;
    652 
    653   // sanity checks
    654   if (!string or !string->b) {
    655     return(NULL);
    656   }
    657   if (string->alloc == 0 and string->len > 0) {
    658     // string is not allocated so it is readonly
    659     return(NULL);
    660   }
    661 
    662   len = (int64_t)string->len;
    663   if (index >= len) {
    664     return(NULL);
    665   }
    666   if (index < -len) {
    667     return(NULL);
    668   }
    669   if (index < 0) {
    670     index = len + index;
    671   }
    672 
    673   // when index == len-1 only decrement len, delete last char and there is nothing to move
    674   if (index < len-1) {
    675     memmove(string->b+index, string->b+index+1, string->len - index-1);
    676   }
    677   string->len--;
    678   return string;
    679 }
    680 
    681 /**
    682  * read file to new btt
    683  *
    684  * The function allocates the buffer
    685  *
    686  * \param
    687  *   filePath path to file
    688  * \return
    689  *   data from file in a btt (you must free the pointer)
    690  *   (btt).b==NULL error
    691  */
    692 btt readFileB(const char *filePath) {
    693   btt r       = init0Var;
    694   ssize_t len = readFile(filePath, (void**)&r.b);
    695   if (len == -1) {
    696     r.b = NULL;
    697     return r;
    698   }
    699   r.len = r.alloc = len;
    700   return r;
    701 }
    702 
    703 /**
    704  * write btt to file
    705  *
    706  * \param
    707  *   filePath path to file
    708  *   btt
    709  * \return
    710  *   1 success
    711  *   0 error
    712  */
    713 int writeFileB(const char *filePath, btt b) {
    714   // sanity checks
    715   if (!b.b) {
    716     return 0;
    717   }
    718   return writeFile(filePath, b.b, b.len);
    719 }
    720 
    721 int64_t findCharB(btt b, const char *needle) {
    722   if (!b.b or !needle ) ret -1;
    723   u8 *p = memmem(b.b, b.len, needle, strlen(needle));
    724   if (!p) ret -1;
    725   ret (int64_t)(p - b.b);
    726 }
    727 
    728 /**
    729  * split b in vb static vector
    730  * the vector is not reallocated
    731  */
    732 vbtt *sasplitB(vbtt *vb, const btt b, const btt delim) {
    733   if (!vb or !b.b or !delim.b) ret null;
    734 
    735   vb->count = 0;
    736 
    737   if (!delim.len or !b.len) {
    738     // empty delimiter empty string, return string in a list
    739     if (vb->count >= vb->maxCount) ret null;
    740     vectorAppend(vb, b);
    741     ret vb;
    742   }
    743 
    744   u8 *working        = b.b;
    745   u8 *nextTokenStart = working;
    746   u32 i              = 0;
    747   if (delim.len == 1) {
    748     while (i < b.len) {
    749       u8 *ptr = memchr(working, delim.b[0], b.len-i);
    750       if (!ptr)
    751         break;
    752       if (vb->count >= vb->maxCount) ret null;
    753       nextTokenStart = ptr + 1;
    754       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
    755       vectorAppend(vb, tok);
    756       i += tok.len + delim.len;
    757       working = b.b + i;
    758     }
    759   }
    760   else {
    761     while (i < b.len) {
    762       u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
    763       if (!ptr)
    764         break;
    765       if (vb->count >= vb->maxCount) ret null;
    766       nextTokenStart = ptr + delim.len;
    767       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
    768       vectorAppend(vb, tok);
    769       i += tok.len + delim.len;
    770       working = b.b + i;
    771     }
    772   }
    773   if (vb->count >= vb->maxCount) ret null;
    774   btt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
    775   vectorAppend(vb, tok);
    776 
    777   ret vb;
    778 }
    779 
    780 /**
    781  * split b in vb static vector
    782  * the vector is not reallocated
    783  */
    784 vbtt *sasplitCharB(vbtt *vb, const btt b, char *delim) {
    785   btt d = ccharB(delim);
    786   ret sasplitB(vb, b, d);
    787 }
    788 
    789 /**
    790  * split b in vb static vector
    791  * the vector is not reallocated
    792  */
    793 vbtt *sasplitDPB(vbtt *vb, const btt b, const btt *delim) {
    794   if (!delim) ret null;
    795   ret sasplitB(vb, b, *delim);
    796 }
    797 
    798 /**
    799  * split b in vb static vector
    800  * the vector is not reallocated
    801  */
    802 vbtt *sasplitPB(vbtt *vb, const btt *b, const btt delim) {
    803   if (!b) ret null;
    804   ret sasplitB(vb, *b, delim);
    805 }
    806 
    807 /**
    808  * split b in vb static vector
    809  * the vector is not reallocated
    810  */
    811 vbtt *sasplitPCharB(vbtt *vb, const btt *b, char *delim) {
    812   if (!b) ret null;
    813   ret sasplitCharB(vb, *b, delim);
    814 }
    815 
    816 /**
    817  * split b in vb static vector
    818  * the vector is not reallocated
    819  */
    820 vbtt *sasplitPDPB(vbtt *vb, const btt *b, const btt *delim) {
    821   if (!b or !delim) ret null;
    822   ret sasplitB(vb, *b, *delim);
    823 }
    824 
    825 /**
    826  * allocate elements
    827  * only when the vector is full
    828  */
    829 #undef vectorAlloc
    830 #define vectorAlloc(name) do{\
    831     if (!(name)->array) {\
    832       (name)->array    = malloc(vectorSz * sizeof (name)->array[0]);\
    833       (name)->maxCount = vectorSz;\
    834     }\
    835     else {\
    836       u32 length    = (name)->count * sizeof (name)->array[0];\
    837       u32 alloc     = (name)->maxCount * sizeof (name)->array[0];\
    838       u32 addlength = sizeof (name)->array[0];\
    839       u32 newsize = makeRoom(length,\
    840                              alloc,\
    841                              addlength\
    842                             );\
    843       (name)->maxCount = newsize / sizeof (name)->array[0];\
    844       (name)->array    = realloc((name)->array, newsize);\
    845     }\
    846   } while(0)
    847 
    848 /**
    849  * split b in vb vector
    850  */
    851 vbtt *asplitB(vbtt *vb, const btt b, const btt delim) {
    852   if (!vb or !b.b or !delim.b) ret null;
    853 
    854   vb->count = 0;
    855 
    856   if (!delim.len or !b.len) {
    857     // empty delimiter empty string, return string in a list
    858     vectorAppend(vb, b);
    859     ret vb;
    860   }
    861 
    862   u8 *working        = b.b;
    863   u8 *nextTokenStart = working;
    864   u32 i              = 0;
    865   if (delim.len == 1) {
    866     while (i < b.len) {
    867       u8 *ptr = memchr(working, delim.b[0], b.len-i);
    868       if (!ptr)
    869         break;
    870       nextTokenStart = ptr + 1;
    871       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
    872       vectorAppend(vb, tok);
    873       i += tok.len + delim.len;
    874       working = b.b + i;
    875     }
    876   }
    877   else {
    878     while (i < b.len) {
    879       u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
    880       if (!ptr)
    881         break;
    882       nextTokenStart = ptr + delim.len;
    883       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
    884       vectorAppend(vb, tok);
    885       i += tok.len + delim.len;
    886       working = b.b + i;
    887     }
    888   }
    889   btt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
    890   vectorAppend(vb, tok);
    891 
    892   ret vb;
    893 }
    894 
    895 /**
    896  * split b in vb vector
    897  */
    898 vbtt *asplitCharB(vbtt *vb, const btt b, char *delim) {
    899   btt d = ccharB(delim);
    900   ret asplitB(vb, b, d);
    901 }
    902 
    903 /**
    904  * split b in vb vector
    905  */
    906 vbtt *asplitDPB(vbtt *vb, const btt b, const btt *delim) {
    907   if (!delim) ret null;
    908   ret asplitB(vb, b, *delim);
    909 }
    910 
    911 /**
    912  * split b in vb vector
    913  */
    914 vbtt *asplitPB(vbtt *vb, const btt *b, const btt delim) {
    915   if (!b) ret null;
    916   ret asplitB(vb, *b, delim);
    917 }
    918 
    919 /**
    920  * split b in vb vector
    921  */
    922 vbtt *asplitPCharB(vbtt *vb, const btt *b, char *delim) {
    923   if (!b) ret null;
    924   ret asplitCharB(vb, *b, delim);
    925 }
    926 
    927 /**
    928  * split b in vb vector
    929  */
    930 vbtt *asplitPDPB(vbtt *vb, const btt *b, const btt *delim) {
    931   if (!b or !delim) ret null;
    932   ret asplitB(vb, *b, *delim);
    933 }
    934 
    935 /**
    936  * return vbtt vector with tokens from b
    937  * this function has good performance for small element counts
    938  */
    939 vbtt splitB(const btt b, const btt delim) {
    940   vbtt r;
    941   if (!b.b or !delim.b) ret emptyvbt;
    942 
    943   vectorInitCount(&r, 5);
    944 
    945   asplitB(&r, b, delim);
    946 
    947   ret r;
    948 }
    949 
    950 /**
    951  * return vbtt vector with tokens from b
    952  * this function has good performance for small element counts
    953  */
    954 vbtt splitCharB(const btt b, char *delim) {
    955   vbtt r;
    956 
    957   if (!b.b or !delim) ret emptyvbt;
    958 
    959   vectorInitCount(&r, 5);
    960 
    961   btt d = ccharB(delim);
    962   asplitB(&r, b, d);
    963 
    964   ret r;
    965 }
    966 
    967 /**
    968  * split b in vb vector
    969  */
    970 vbtt splitDPB(const btt b, const btt *delim) {
    971   if (!delim) ret emptyvbt;
    972   ret splitB(b, *delim);
    973 }
    974 
    975 /**
    976  * split b in vb vector
    977  */
    978 vbtt splitPB(const btt *b, const btt delim) {
    979   if (!b) ret emptyvbt;
    980   ret splitB(*b, delim);
    981 }
    982 
    983 /**
    984  * return vbtt vector with tokens from b
    985  * this function has good performance for small element counts
    986  */
    987 vbtt splitPCharB(const btt *b, char *delim) {
    988   if (!b) ret emptyvbt;
    989   ret splitCharB(*b, delim);
    990 }
    991 
    992 /**
    993  * split b in vb vector
    994  */
    995 vbtt splitPDPB(const btt *b, const btt *delim) {
    996   if (!b or !delim) ret emptyvbt;
    997   ret splitB(*b, *delim);
    998 }
    999 
   1000 /**
   1001  * return dbtt vector with tokens from b
   1002  * this function has good performance for large element counts
   1003  */
   1004 dbtt dsplitB(const btt b, const btt delim) {
   1005   dbtt r;
   1006 
   1007   if (!b.b or !delim.b) ret emptydbt;
   1008 
   1009   dVectorInit(&r);
   1010 
   1011   if (!delim.len or !b.len) {
   1012     // empty delimiter empty string, return string in a list
   1013     dVectorAppend(&r, b);
   1014     ret r;
   1015   }
   1016 
   1017   u8 *working        = b.b;
   1018   u8 *nextTokenStart = working;
   1019   u32 i              = 0;
   1020   if (delim.len == 1) {
   1021     while (i < b.len) {
   1022       u8 *ptr = memchr(working, delim.b[0], b.len-i);
   1023       if (!ptr)
   1024         break;
   1025       nextTokenStart = ptr + 1;
   1026       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
   1027       dVectorAppend(&r, tok);
   1028       i += tok.len + delim.len;
   1029       working = b.b + i;
   1030     }
   1031   }
   1032   else {
   1033     while (i < b.len) {
   1034       u8 *ptr = memmem(working, b.len-i, delim.b, delim.len);
   1035       if (!ptr)
   1036         break;
   1037       nextTokenStart = ptr + delim.len;
   1038       btt tok = {.b = working, .len = ptr-working, .alloc = 0};
   1039       dVectorAppend(&r, tok);
   1040       i += tok.len + delim.len;
   1041       working = b.b + i;
   1042     }
   1043   }
   1044   btt tok = {.b = nextTokenStart, .len = (b.b+b.len)-nextTokenStart, .alloc = 0};
   1045   dVectorAppend(&r, tok);
   1046 
   1047   ret r;
   1048 }
   1049 
   1050 /**
   1051  * return dbtt vector with tokens from b
   1052  * this function has good performance for large element counts
   1053  */
   1054 dbtt dsplitCharB(const btt b, char *delim) {
   1055   btt d = ccharB(delim);
   1056   ret dsplitB(b, d);
   1057 }
   1058 
   1059 /**
   1060  * return dbtt vector with tokens from b
   1061  * this function has good performance for large element counts
   1062  */
   1063 dbtt dsplitDPB(const btt b, const btt *delim) {
   1064   if (!delim) ret emptydbt;
   1065   ret dsplitB(b, *delim);
   1066 }
   1067 
   1068 /**
   1069  * return dbtt vector with tokens from b
   1070  * this function has good performance for large element counts
   1071  */
   1072 dbtt dsplitPB(const btt *b, const btt delim) {
   1073   if (!b) ret emptydbt;
   1074   ret dsplitB(*b, delim);
   1075 }
   1076 
   1077 /**
   1078  * return dbtt vector with tokens from b
   1079  * this function has good performance for large element counts
   1080  */
   1081 dbtt dsplitPCharB(const btt *b, char *delim) {
   1082   if (!b) ret emptydbt;
   1083   ret dsplitCharB(*b, delim);
   1084 }
   1085 
   1086 /**
   1087  * return dbtt vector with tokens from b
   1088  * this function has good performance for large element counts
   1089  */
   1090 dbtt dsplitPDPB(const btt *b, const btt *delim) {
   1091   if (!b or !delim) ret emptydbt;
   1092   ret dsplitB(*b, *delim);
   1093 }
   1094 
   1095 /**
   1096  * slice String
   1097  * return a btt object which is the string between start and end
   1098  * negative indexes are allowed
   1099  */
   1100 btt sliceB(const btt b, int64_t start, int64_t end) {
   1101   btt r = {0};
   1102   if (!b.b) ret emptybt;
   1103 
   1104   #define checkRange(B, rval)\
   1105   i64 len = (B).len;\
   1106   if (start > len)\
   1107     ret rval;\
   1108   if (end > len)\
   1109     end = len;\
   1110   if (start <= -len)\
   1111     start = -len;\
   1112   if (end <= -len)\
   1113     ret rval;\
   1114   if (start < 0)\
   1115     start = len + start;\
   1116   if (end <= 0)\
   1117     end = len + end;\
   1118   if (end < start)\
   1119     ret rval
   1120   checkRange(b, emptybt);
   1121 
   1122   r.b   = b.b + start;
   1123   if (start == end) {
   1124     // empty string
   1125     r.len = 0;
   1126   }
   1127   else {
   1128     // start < end < len
   1129     r.len = end - start;
   1130   }
   1131   ret r;
   1132 }
   1133 
   1134 /**
   1135  * slice String
   1136  * update the b btt object and keep only the string between start and end
   1137  * negative indexes are allowed
   1138  */
   1139 btt *bSliceB(btt *b, int64_t start, int64_t end) {
   1140   if (!b) ret null;
   1141 
   1142   checkRange(*b, null);
   1143 
   1144   if (start == end) {
   1145     // empty string
   1146     b->len = 0;
   1147   }
   1148   else {
   1149     // start < end < len
   1150     b->len = end - start;
   1151     if (start)
   1152       memmove(b->b, b->b+start, b->len);
   1153   }
   1154   ret b;
   1155 }
   1156 
   1157 /**
   1158  * slice String
   1159  * return a btt object which is the string between start and end
   1160  * negative indexes are allowed
   1161  */
   1162 btt slicePB(const btt *b, int64_t start, int64_t end) {
   1163   if (!b) ret emptybt;
   1164   ret sliceB(*b, start, end);
   1165 }
   1166 
   1167 /**
   1168  * join list, the elements are seperated with delim in the resulting string
   1169  *
   1170  * \param
   1171  *   list
   1172  * \param
   1173  *   delim: string seperator
   1174  * \return
   1175  *   joined string (you must free the btt)
   1176  *   empty when list or delim are NULL
   1177  */
   1178 btt joinCharB(vbtt list, const char* delim) {
   1179   btt r = {0};
   1180 
   1181   // sanity checks
   1182   if (!delim) {
   1183     return r;
   1184   }
   1185 
   1186   vectorForEach(&list, e) {
   1187     if (!r.b) {
   1188       r = copyB(*e);
   1189     }
   1190     else {
   1191       // TODO check return value
   1192       bPushB(&r, delim);
   1193       bPushBB(&r, *e);
   1194     }
   1195   }
   1196   return(r);
   1197 }
   1198 
   1199 
   1200 btt copyRngB(const btt b, int64_t start, int64_t end) {
   1201   btt s = sliceB(b, start, end);
   1202   if (not s.b) ret s; // error return {0}
   1203   else         ret copyB(s);
   1204 }
   1205 
   1206 // cropB copy and remove
   1207 btt bCropB(btt *b, int64_t start, int64_t end) {
   1208 
   1209   // sanity checks
   1210   if (!b or !b->b) {
   1211     ret emptybt;
   1212   }
   1213   if (b->alloc == 0 and b->len > 0) {
   1214     // b is not allocated so it is readonly
   1215     ret emptybt;
   1216   }
   1217 
   1218   checkRange(*b, emptybt);
   1219 
   1220   // slice to s
   1221   btt s = {0};
   1222   s.b   = b->b + start;
   1223   if (start == end) {
   1224     // empty string
   1225     s.len = 0;
   1226     ret s; // nothing to delete in b
   1227   }
   1228   else {
   1229     // start < end < len
   1230     s.len = end - start;
   1231   }
   1232 
   1233   // copy s to r and allocate on heap
   1234   btt r;
   1235   r.len = s.len;
   1236   r.b     = malloc(r.len);
   1237   r.alloc = r.len;
   1238   memcpy(r.b, s.b, r.len);
   1239 
   1240   // delete string between start and end in b
   1241   // copy range to a new string
   1242   int64_t n;
   1243   n = end - start;
   1244   memmove(b->b+start, b->b+start+n, (size_t)(len-n-start));
   1245   b->len -= n;
   1246 
   1247   ret r;
   1248 }
   1249 
   1250 /**
   1251  * return a btt object without the leading and trailing spaces
   1252  */
   1253 btt trimB(const btt b) {
   1254   btt r = {0};
   1255   if (!b.b) ret emptybt;
   1256 
   1257   r.b = b.b;
   1258 
   1259   u32 i = 0;
   1260 
   1261   // remove leading spaces
   1262   while (i < b.len and isspace(*r.b)) {
   1263     i++; r.b++;
   1264   }
   1265 
   1266   if (i == b.len) {
   1267     // all spaces
   1268     r.b     = b.b;
   1269     ret r;
   1270   }
   1271 
   1272   // remove trailing spaces
   1273   u8 *end = b.b + b.len - 1;
   1274   while (isspace(*end))
   1275     end--;
   1276 
   1277   r.len = end - r.b + 1;
   1278 
   1279   ret r;
   1280 }
   1281 
   1282 /**
   1283  * update b btt object and remove the leading and trailing spaces
   1284  */
   1285 // memmove data
   1286 btt *bTrimB(btt *b) {
   1287   if (!b or !b->b) ret null;
   1288 
   1289   btt t = trimB(*b);
   1290 
   1291   if (t.b != b->b)
   1292     memmove(b->b, t.b, t.len);
   1293   b->len = t.len;
   1294 
   1295   ret b;
   1296 }
   1297 
   1298 /**
   1299  * return a btt object without the leading and trailing spaces
   1300  */
   1301 btt trimPB(const btt *b) {
   1302   if (!b) emptybt;
   1303   ret trimB(*b);
   1304 }
   1305 
   1306 /**
   1307  * remove empty strings from list
   1308  *
   1309  * \param
   1310  *   list
   1311  * \return
   1312  *   list without empty strings
   1313  *   empty list when list is empty
   1314  *   unchanged list when list is NULL
   1315  *   NULL error
   1316  */
   1317 vbtt *bCompactB(vbtt *list) {
   1318 
   1319   // sanity checks
   1320   if (!list) {
   1321     return(NULL);
   1322   }
   1323 
   1324   u16 rindex = 0;
   1325   // keep non empty elements
   1326   vectorForEach(list, e) {
   1327     trimBG(e);
   1328     if (not isEmptyPB(e)) {
   1329       list->array[rindex++] = *e;
   1330     }
   1331     else {
   1332       freenB(e);
   1333     }
   1334   }
   1335   list->count = rindex;
   1336   return(list);
   1337 }
   1338 
   1339 /**
   1340  * buffer size normalize path
   1341  *
   1342  * remove unecessary /, .. and .
   1343  * leading / is kept
   1344  * leading .. is kept
   1345  * leading . is removed
   1346  *
   1347  * '/../' becomes '/'
   1348  *
   1349  * \param
   1350  *   path
   1351  * \return
   1352  *   path modified path
   1353  *   NULL when path is NULL
   1354  */
   1355 btt *bNormalizePathB(btt *path) {
   1356 
   1357   // sanity checks
   1358   if (!path) {
   1359     return(NULL);
   1360   }
   1361 
   1362   if (!path->len) {
   1363     return(path);
   1364   }
   1365 
   1366   if (isEmptyPB(path)) {
   1367     return(path);
   1368   }
   1369 
   1370   // list path elements
   1371   vbtt pathL = splitBG(path, "/");
   1372 
   1373   // remove empty elements
   1374   bCompactB(&pathL);
   1375 
   1376   if (pathL.count == 0) {
   1377     vectorFree(&pathL);
   1378     // keep leading /
   1379     path->b[0] = '/';
   1380     path->len  = 1;
   1381     return(path);
   1382   }
   1383 
   1384   // new path elements
   1385   vbtt list;
   1386   vectorInitCount(&list, pathL.count);
   1387 
   1388   // detect leading double dots
   1389   bool onlyLeadingDoubleDots = true;
   1390 
   1391   // add elements to list
   1392   vectorForEach(&pathL, level) {
   1393     if (eqCharB(*level, "..")) {
   1394       if (onlyLeadingDoubleDots) {
   1395         // keep leading ..
   1396         vectorAppend(&list, charB(strdup("..")));
   1397       }
   1398       else {
   1399         // remove .. in path
   1400         if (list.count) {
   1401           btt s = vectorPop(&list);
   1402           freeB(s);
   1403         }
   1404       }
   1405     }
   1406     else if (!eqCharB(*level, ".")) {
   1407       // remove . and add elements
   1408       btt c = copyB(*level);
   1409       vectorAppend(&list, c);
   1410       // an element is pushed, so this is the end of leading double dots
   1411       onlyLeadingDoubleDots = false;
   1412     }
   1413   }
   1414 
   1415   if (list.count == 1 && eqCharB(vectorAt(&list, 0), "..") && path->b[0] == '/') {
   1416     // handle ../ .. /.. /../
   1417     vectorAt(&list, 0).len = 0;
   1418   }
   1419 
   1420   // handle /.: add empty string
   1421   if (eqCharB(*path, "/.")) {
   1422     btt c = newB(4);
   1423     vectorAppend(&list, c);
   1424   }
   1425 
   1426   // keep leading /
   1427   if (path->b[0] == '/') {
   1428     if (list.count == 0) {
   1429       // .. cancelled path: /a/b/../..
   1430       vectorFree(&pathL);
   1431       vectorFree(&list);
   1432       path->len = 1;
   1433       return(path);
   1434     }
   1435     //why? pErrorNULL(listPrependS(&list, ""));
   1436   }
   1437 
   1438   // create new path
   1439   btt r = joinCharB(list, "/");
   1440   vectorFree(&pathL);
   1441   vectorFree(&list);
   1442   if (!r.b) {
   1443     path->len = 0;
   1444     return(path);
   1445   }
   1446   // TODO check null
   1447   setValB(path, &r);
   1448   return(path);
   1449 }
   1450 
   1451 void printB(const btt b) {
   1452   write(STDOUT_FILENO, b.b, b.len);
   1453 }
   1454 
   1455 void printDebugB(const btt b) {
   1456   write(STDOUT_FILENO, "\"", 1);
   1457   printB(b);
   1458   write(STDOUT_FILENO, "\"", 1);
   1459   put;
   1460 }
   1461 
   1462 void printDebugInfoB(const btt b) {
   1463   logD("b: %p, len: %"PRIu32", alloc: %"PRIu32, b.b, b.len, b.alloc);
   1464   printDebugB(b);
   1465 }
   1466 // vim: set expandtab ts=2 sw=2: