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: