xs.h (38012B)
1 /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ 2 3 #ifndef _XS_H 4 5 #define _XS_H 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <stdlib.h> 10 #include <ctype.h> 11 #include <unistd.h> 12 #include <stdarg.h> 13 #include <signal.h> 14 #include <errno.h> 15 #include <stdint.h> 16 17 typedef enum { 18 XSTYPE_STRING = 0x02, /* C string (\0 delimited) (NOT STORED) */ 19 XSTYPE_NUMBER = 0x17, /* double in spirit, stored as a C string (\0 delimited) */ 20 XSTYPE_NULL = 0x18, /* Special NULL value */ 21 XSTYPE_TRUE = 0x06, /* Boolean */ 22 XSTYPE_FALSE = 0x15, /* Boolean */ 23 XSTYPE_LIST = 0x1d, /* Sequence of LITEMs up to EOM (with size) */ 24 XSTYPE_LITEM = 0x1f, /* Element of a list (any type) */ 25 XSTYPE_DICT = 0x1c, /* Sequence of KEYVALs up to EOM (with size) */ 26 XSTYPE_KEYVAL = 0x1e, /* key + value (STRING key + any type) */ 27 XSTYPE_DATA = 0x10 /* A block of anonymous data */ 28 } xstype; 29 30 31 /* types */ 32 typedef char xs_val; 33 typedef char xs_str; 34 typedef char xs_list; 35 typedef char xs_keyval; 36 typedef char xs_dict; 37 typedef char xs_number; 38 typedef char xs_data; 39 typedef struct { 40 xs_str *data; 41 int len; 42 } xs_str_bld; 43 44 /* size in bytes of the type size */ 45 #define _XS_TYPE_SIZE 4 46 47 /* auto-destroyable strings */ 48 #define xs __attribute__ ((__cleanup__ (_xs_destroy))) xs_val 49 50 /* not really all, just very much */ 51 #define XS_ALL 0xfffffff 52 53 #ifndef xs_countof 54 #define xs_countof(a) (sizeof((a)) / sizeof((*a))) 55 #endif 56 57 void *xs_free(void *ptr); 58 void *_xs_realloc(void *ptr, size_t size, const char *file, int line, const char *func); 59 #define xs_realloc(ptr, size) _xs_realloc(ptr, size, __FILE__, __LINE__, __func__) 60 int _xs_blk_size(int sz); 61 void _xs_destroy(char **var); 62 #define xs_debug() raise(SIGTRAP) 63 xstype xs_type(const xs_val *data); 64 int xs_size(const xs_val *data); 65 int xs_is_null(const xs_val *data); 66 int xs_cmp(const xs_val *v1, const xs_val *v2); 67 const xs_val *xs_or(const xs_val *v1, const xs_val *v2); 68 xs_val *xs_dup(const xs_val *data); 69 xs_val *xs_expand(xs_val *data, int offset, int size); 70 xs_val *xs_collapse(xs_val *data, int offset, int size); 71 xs_val *xs_insert_m(xs_val *data, int offset, const char *mem, int size); 72 #define xs_insert(data, offset, data2) xs_insert_m(data, offset, data2, xs_size(data2)) 73 #define xs_append_m(data, mem, size) xs_insert_m(data, xs_size(data) - 1, mem, size) 74 xs_val *xs_stock(int type); 75 76 xs_str *xs_str_new(const char *str); 77 xs_str *xs_str_new_sz(const char *mem, int sz); 78 xs_str *xs_str_wrap_i(const char *prefix, xs_str *str, const char *suffix); 79 #define xs_str_prepend_i(str, prefix) xs_str_wrap_i(prefix, str, NULL) 80 xs_str *_xs_str_cat(xs_str *str, const char *strs[]); 81 #define xs_str_cat(str, ...) _xs_str_cat(str, (const char *[]){ __VA_ARGS__, NULL }) 82 xs_str *xs_str_cat_fmt(xs_str *str, const char *fmt, ...); 83 void xs_str_bld_cat(xs_str_bld *b, const char *str); 84 void xs_str_bld_cat_fmt(xs_str_bld *b, const char *fmt, ...); 85 xs_str *xs_replace_in(xs_str *str, const char *sfrom, const char *sto, int times); 86 #define xs_replace_i(str, sfrom, sto) xs_replace_in(str, sfrom, sto, XS_ALL) 87 #define xs_replace(str, sfrom, sto) xs_replace_in(xs_dup(str), sfrom, sto, XS_ALL) 88 #define xs_replace_n(str, sfrom, sto, times) xs_replace_in(xs_dup(str), sfrom, sto, times) 89 xs_str *xs_fmt(const char *fmt, ...); 90 int xs_str_in(const char *haystack, const char *needle); 91 int xs_between(const char *prefix, const char *str, const char *suffix); 92 #define xs_startswith(str, prefix) xs_between(prefix, str, NULL) 93 #define xs_endswith(str, suffix) xs_between(NULL, str, suffix) 94 xs_str *xs_crop_i(xs_str *str, int start, int end); 95 xs_str *xs_lstrip_chars_i(xs_str *str, const char *chars); 96 xs_str *xs_rstrip_chars_i(xs_str *str, const char *chars); 97 xs_str *xs_strip_chars_i(xs_str *str, const char *chars); 98 #define xs_strip_i(str) xs_strip_chars_i(str, " \r\n\t\v\f") 99 xs_str *xs_tolower_i(xs_str *str); 100 101 xs_list *xs_list_new(void); 102 xs_list *xs_list_append_m(xs_list *list, const char *mem, int dsz); 103 xs_list *_xs_list_append(xs_list *list, const xs_val *vals[]); 104 #define xs_list_append(list, ...) _xs_list_append(list, (const xs_val *[]){ __VA_ARGS__, NULL }) 105 int xs_list_iter(xs_list **list, const xs_val **value); 106 int xs_list_next(const xs_list *list, const xs_val **value, int *ctxt); 107 int xs_list_len(const xs_list *list); 108 const xs_val *xs_list_get(const xs_list *list, int num); 109 xs_list *xs_list_del(xs_list *list, int num); 110 xs_list *xs_list_insert(xs_list *list, int num, const xs_val *data); 111 xs_list *xs_list_set(xs_list *list, int num, const xs_val *data); 112 xs_list *xs_list_dequeue(xs_list *list, xs_val **data, int last); 113 #define xs_list_pop(list, data) xs_list_dequeue(list, data, 1) 114 #define xs_list_shift(list, data) xs_list_dequeue(list, data, 0) 115 int xs_list_in(const xs_list *list, const xs_val *val); 116 xs_str *xs_join(const xs_list *list, const char *sep); 117 xs_list *xs_split_n(const char *str, const char *sep, int times); 118 #define xs_split(str, sep) xs_split_n(str, sep, XS_ALL) 119 xs_list *xs_list_cat(xs_list *l1, const xs_list *l2); 120 121 int xs_keyval_size(const xs_str *key, const xs_val *value); 122 xs_str *xs_keyval_key(const xs_keyval *keyval); 123 xs_val *xs_keyval_value(const xs_keyval *keyval); 124 xs_keyval *xs_keyval_make(xs_keyval *keyval, const xs_str *key, const xs_val *value); 125 126 xs_dict *xs_dict_new(void); 127 xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value); 128 xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value); 129 int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value, int *ctxt); 130 const xs_val *xs_dict_get(const xs_dict *dict, const xs_str *key); 131 #define xs_dict_get_def(dict, key, def) xs_or(xs_dict_get(dict, key), def) 132 xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key); 133 xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data); 134 xs_dict *xs_dict_set_strnn(xs_dict *dict, const void *key, int klen, const void *val, int vlen); 135 xs_dict *xs_dict_set_fmt(xs_dict *dict, const xs_str *key, const char *fmt, ...); 136 xs_dict *xs_dict_gc(const xs_dict *dict); 137 138 const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep); 139 #define xs_dict_get_path(dict, path) xs_dict_get_path_sep(dict, path, ".") 140 xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep); 141 #define xs_dict_set_path(dict, path, value) xs_dict_set_path_sep(dict, path, value, ".") 142 143 xs_val *xs_val_new(xstype t); 144 xs_number *xs_number_new(double f); 145 double xs_number_get(const xs_number *v); 146 const char *xs_number_str(const xs_number *v); 147 148 xs_data *xs_data_new(const void *data, int size); 149 int xs_data_size(const xs_data *value); 150 void xs_data_get(void *data, const xs_data *value); 151 152 void *xs_memmem(const char *haystack, int h_size, const char *needle, int n_size); 153 154 unsigned int xs_hash_func(const char *data, int size); 155 uint64_t xs_hash64_func(const char *data, int size); 156 157 #ifdef XS_ASSERT 158 #include <assert.h> 159 #define XS_ASSERT_TYPE(v, t) assert(xs_type(v) == t) 160 #define XS_ASSERT_TYPE_NULL(v, t) assert(v == NULL || xs_type(v) == t) 161 #else 162 #define XS_ASSERT_TYPE(v, t) (void)(0) 163 #define XS_ASSERT_TYPE_NULL(v, t) (void)(0) 164 #endif 165 166 #define xs_return(v) xs_val *__r = v; v = NULL; return __r 167 168 #define xs_is_true(v) (xs_type((v)) == XSTYPE_TRUE) 169 #define xs_is_false(v) (xs_type((v)) == XSTYPE_FALSE) 170 #define xs_not(v) xs_stock(xs_is_true((v)) ? XSTYPE_FALSE : XSTYPE_TRUE) 171 #define xs_is_string(v) (xs_type((v)) == XSTYPE_STRING) 172 #define xs_is_list(v) (xs_type((v)) == XSTYPE_LIST) 173 #define xs_is_dict(v) (xs_type((v)) == XSTYPE_DICT) 174 175 #define xs_list_foreach(l, v) for (int ct_##__LINE__ = 0; xs_list_next(l, &v, &ct_##__LINE__); ) 176 #define xs_dict_foreach(l, k, v) for (int ct_##__LINE__ = 0; xs_dict_next(l, &k, &v, &ct_##__LINE__); ) 177 178 179 #ifdef XS_IMPLEMENTATION 180 181 void *_xs_realloc(void *ptr, size_t size, const char *file, int line, const char *func) 182 { 183 xs_val *ndata = realloc(ptr, size); 184 185 if (ndata == NULL) { 186 fprintf(stderr, "ERROR: out of memory at %s:%d: %s()\n", file, line, func); 187 abort(); 188 } 189 190 #ifdef XS_DEBUG 191 if (ndata != ptr) { 192 int n; 193 FILE *f = fopen("xs_memory.out", "a"); 194 195 if (ptr != NULL) 196 fprintf(f, "%p r\n", ptr); 197 198 fprintf(f, "%p a %ld %s:%d: %s", ndata, size, file, line, func); 199 200 if (ptr != NULL) { 201 fprintf(f, " ["); 202 for (n = 0; n < 32 && ndata[n]; n++) { 203 if (ndata[n] >= 32 && ndata[n] <= 127) 204 fprintf(f, "%c", ndata[n]); 205 else 206 fprintf(f, "\\%02x", (unsigned char)ndata[n]); 207 } 208 fprintf(f, "]"); 209 } 210 211 fprintf(f, "\n"); 212 213 fclose(f); 214 } 215 #else 216 (void)file; 217 (void)line; 218 (void)func; 219 #endif 220 221 return ndata; 222 } 223 224 225 void *xs_free(void *ptr) 226 { 227 #ifdef XS_DEBUG 228 if (ptr != NULL) { 229 FILE *f = fopen("xs_memory.out", "a"); 230 fprintf(f, "%p b\n", ptr); 231 fclose(f); 232 } 233 #endif 234 235 free(ptr); 236 return NULL; 237 } 238 239 240 void _xs_destroy(char **var) 241 { 242 /* 243 if (_xs_debug) 244 printf("_xs_destroy %p\n", var); 245 */ 246 xs_free(*var); 247 } 248 249 250 int _xs_blk_size(int sz) 251 /* calculates the block size */ 252 { 253 int blk_size = 4096; 254 255 if (sz < 256) 256 blk_size = 32; 257 else 258 if (sz < 4096) 259 blk_size = 256; 260 261 return ((((sz) + blk_size - 1) / blk_size) * blk_size); 262 } 263 264 265 xstype xs_type(const xs_val *data) 266 /* return the type of data */ 267 { 268 xstype t; 269 270 if (data == NULL) 271 t = XSTYPE_NULL; 272 else 273 switch (data[0]) { 274 case XSTYPE_NULL: 275 case XSTYPE_TRUE: 276 case XSTYPE_FALSE: 277 case XSTYPE_LIST: 278 case XSTYPE_LITEM: 279 case XSTYPE_DICT: 280 case XSTYPE_KEYVAL: 281 case XSTYPE_NUMBER: 282 case XSTYPE_DATA: 283 t = data[0]; 284 break; 285 default: 286 t = XSTYPE_STRING; 287 break; 288 } 289 290 return t; 291 } 292 293 294 void _xs_put_size(xs_val *ptr, int i) 295 /* must match _XS_TYPE_SIZE */ 296 { 297 memcpy(ptr + 1, &i, sizeof(i)); 298 } 299 300 301 int _xs_get_size(const xs_val *ptr) 302 /* must match _XS_TYPE_SIZE */ 303 { 304 int i; 305 memcpy(&i, ptr + 1, sizeof(i)); 306 return i; 307 } 308 309 310 int xs_size(const xs_val *data) 311 /* returns the size of data in bytes */ 312 { 313 int len = 0; 314 const char *p; 315 316 if (data == NULL) 317 return 0; 318 319 switch (xs_type(data)) { 320 case XSTYPE_STRING: 321 len = strlen(data) + 1; 322 break; 323 324 case XSTYPE_LIST: 325 case XSTYPE_DICT: 326 case XSTYPE_DATA: 327 len = _xs_get_size(data); 328 329 break; 330 331 case XSTYPE_KEYVAL: 332 /* calculate the size of the key and the value */ 333 p = data + 1; 334 p += xs_size(p); 335 p += xs_size(p); 336 337 len = p - data; 338 339 break; 340 341 case XSTYPE_LITEM: 342 /* it's the size of the item + 1 */ 343 p = data + 1; 344 p += xs_size(p); 345 346 len = p - data; 347 348 break; 349 350 case XSTYPE_NUMBER: 351 len = 1 + xs_size(data + 1); 352 353 break; 354 355 default: 356 len = 1; 357 } 358 359 return len; 360 } 361 362 363 int xs_is_null(const xs_val *data) 364 /* checks for null */ 365 { 366 return (xs_type(data) == XSTYPE_NULL); 367 } 368 369 370 int xs_cmp(const xs_val *v1, const xs_val *v2) 371 /* compares two values */ 372 { 373 if (xs_type(v1) == XSTYPE_STRING && xs_type(v2) == XSTYPE_STRING) 374 return strcmp(v1, v2); 375 376 int s1 = xs_size(v1); 377 int s2 = xs_size(v2); 378 int d = s1 - s2; 379 380 return d == 0 ? memcmp(v1, v2, s1) : d; 381 } 382 383 384 const xs_val *xs_or(const xs_val *v1, const xs_val *v2) 385 /* returns v1 if it's not NULL, else v2 */ 386 { 387 return v1 == NULL ? v2 : v1; 388 } 389 390 391 xs_val *xs_dup(const xs_val *data) 392 /* creates a duplicate of data */ 393 { 394 xs_val *s = NULL; 395 396 if (data) { 397 int sz = xs_size(data); 398 s = xs_realloc(NULL, _xs_blk_size(sz)); 399 400 memcpy(s, data, sz); 401 } 402 403 return s; 404 } 405 406 407 xs_val *xs_expand(xs_val *data, int offset, int size) 408 /* opens a hole in data */ 409 { 410 xstype type = xs_type(data); 411 int sz = xs_size(data) + size; 412 413 /* open room */ 414 data = xs_realloc(data, _xs_blk_size(sz)); 415 416 /* move up the rest of the data */ 417 memmove(data + offset + size, data + offset, sz - offset - size); 418 419 if (type == XSTYPE_LIST || 420 type == XSTYPE_DICT || 421 type == XSTYPE_DATA) 422 _xs_put_size(data, sz); 423 424 return data; 425 } 426 427 428 xs_val *xs_collapse(xs_val *data, int offset, int size) 429 /* shrinks data */ 430 { 431 int sz = xs_size(data); 432 433 /* don't try to delete beyond the limit */ 434 if (offset + size > sz) 435 size = sz - offset; 436 437 /* shrink total size */ 438 sz -= size; 439 440 memmove(data + offset, data + offset + size, sz - offset); 441 442 if (xs_type(data) == XSTYPE_LIST || 443 xs_type(data) == XSTYPE_DICT || 444 xs_type(data) == XSTYPE_DATA) 445 _xs_put_size(data, sz); 446 447 return xs_realloc(data, _xs_blk_size(sz)); 448 } 449 450 451 xs_val *xs_insert_m(xs_val *data, int offset, const char *mem, int size) 452 /* inserts a memory block */ 453 { 454 data = xs_expand(data, offset, size); 455 memcpy(data + offset, mem, size); 456 457 return data; 458 } 459 460 461 xs_val *xs_stock(int type) 462 /* returns stock values */ 463 { 464 static xs_val stock_null[] = { XSTYPE_NULL }; 465 static xs_val stock_true[] = { XSTYPE_TRUE }; 466 static xs_val stock_false[] = { XSTYPE_FALSE }; 467 static xs_val stock_0[] = { XSTYPE_NUMBER, '0', '\0' }; 468 static xs_val stock_1[] = { XSTYPE_NUMBER, '1', '\0' }; 469 static xs_list *stock_list = NULL; 470 static xs_dict *stock_dict = NULL; 471 472 switch (type) { 473 case 0: return stock_0; 474 case 1: return stock_1; 475 case XSTYPE_NULL: return stock_null; 476 case XSTYPE_TRUE: return stock_true; 477 case XSTYPE_FALSE: return stock_false; 478 479 case XSTYPE_LIST: 480 if (stock_list == NULL) 481 stock_list = xs_list_new(); 482 return stock_list; 483 484 case XSTYPE_DICT: 485 if (stock_dict == NULL) 486 stock_dict = xs_dict_new(); 487 return stock_dict; 488 } 489 490 return NULL; 491 } 492 493 494 /** strings **/ 495 496 xs_str *xs_str_new(const char *str) 497 /* creates a new string */ 498 { 499 return xs_insert(NULL, 0, str ? str : ""); 500 } 501 502 503 xs_str *xs_str_new_sz(const char *mem, int sz) 504 /* creates a new string from a memory block, adding an asciiz */ 505 { 506 xs_str *s = xs_realloc(NULL, _xs_blk_size(sz + 1)); 507 memcpy(s, mem, sz); 508 s[sz] = '\0'; 509 510 return s; 511 } 512 513 514 xs_str *xs_str_wrap_i(const char *prefix, xs_str *str, const char *suffix) 515 /* wraps str with prefix and suffix */ 516 { 517 XS_ASSERT_TYPE(str, XSTYPE_STRING); 518 519 if (prefix) 520 str = xs_insert_m(str, 0, prefix, strlen(prefix)); 521 522 if (suffix) 523 str = xs_insert_m(str, strlen(str), suffix, strlen(suffix)); 524 525 return str; 526 } 527 528 xs_str *xs_str_cat_fmt(xs_str *str, const char *fmt, ...) 529 { 530 int o = strlen(str); 531 int n; 532 va_list ap; 533 534 va_start(ap, fmt); 535 n = vsnprintf(NULL, 0, fmt, ap); 536 va_end(ap); 537 538 if (n++ > 0) { 539 str = xs_realloc(str, o + n); 540 va_start(ap, fmt); 541 vsnprintf(str + o, n, fmt, ap); 542 va_end(ap); 543 } 544 545 return str; 546 } 547 548 void xs_str_bld_cat_fmt(xs_str_bld *b, const char *fmt, ...) 549 { 550 int n; 551 va_list ap; 552 553 va_start(ap, fmt); 554 n = vsnprintf(NULL, 0, fmt, ap); 555 va_end(ap); 556 557 if (n > 0) { 558 b->data = xs_realloc(b->data, _xs_blk_size(b->len + n + 1)); 559 va_start(ap, fmt); 560 vsnprintf(b->data + b->len, n + 1, fmt, ap); 561 va_end(ap); 562 563 b->len += n; 564 } 565 } 566 567 void xs_str_bld_cat(xs_str_bld *b, const xs_str *s) 568 { 569 int n = strlen(s); 570 b->data = xs_realloc(b->data, _xs_blk_size(b->len + n + 1)); 571 memcpy(b->data + b->len, s, n + 1); 572 b->len += n; 573 } 574 575 xs_str *_xs_str_cat(xs_str *str, const char *strs[]) 576 /* concatenates all strings after str */ 577 { 578 int o = strlen(str); 579 580 while (*strs) { 581 int sz = strlen(*strs); 582 str = xs_insert_m(str, o, *strs, sz); 583 o += sz; 584 strs++; 585 } 586 587 return str; 588 } 589 590 591 xs_str *xs_replace_in(xs_str *str, const char *sfrom, const char *sto, int times) 592 /* replaces inline all sfrom with sto */ 593 { 594 XS_ASSERT_TYPE(str, XSTYPE_STRING); 595 596 int sfsz = strlen(sfrom); 597 int stsz = strlen(sto); 598 int diff = stsz - sfsz; 599 char *ss; 600 int offset = 0; 601 602 while (times > 0 && (ss = strstr(str + offset, sfrom)) != NULL) { 603 int n_offset = ss - str; 604 605 if (diff < 0) 606 str = xs_collapse(str, n_offset, -diff); 607 else 608 if (diff > 0) 609 str = xs_expand(str, n_offset, diff); 610 611 memcpy(str + n_offset, sto, stsz); 612 613 offset = n_offset + stsz; 614 615 times--; 616 } 617 618 return str; 619 } 620 621 622 xs_str *xs_fmt(const char *fmt, ...) 623 /* formats a string with printf()-like marks */ 624 { 625 int n; 626 xs_str *s = NULL; 627 va_list ap; 628 629 va_start(ap, fmt); 630 n = vsnprintf(s, 0, fmt, ap); 631 va_end(ap); 632 633 if (n > 0) { 634 s = xs_realloc(NULL, _xs_blk_size(n + 1)); 635 636 va_start(ap, fmt); 637 vsnprintf(s, n + 1, fmt, ap); 638 va_end(ap); 639 } 640 641 return s; 642 } 643 644 645 int xs_str_in(const char *haystack, const char *needle) 646 /* finds needle in haystack and returns the offset or -1 */ 647 { 648 char *s; 649 int r = -1; 650 651 if ((s = strstr(haystack, needle)) != NULL) 652 r = s - haystack; 653 654 return r; 655 } 656 657 658 int xs_between(const char *prefix, const char *str, const char *suffix) 659 /* returns true if str starts with prefix and ends with suffix */ 660 { 661 int sz = strlen(str); 662 int psz = prefix ? strlen(prefix) : 0; 663 int ssz = suffix ? strlen(suffix) : 0; 664 665 if (sz < psz || sz < ssz) 666 return 0; 667 668 if (prefix && memcmp(str, prefix, psz) != 0) 669 return 0; 670 671 if (suffix && memcmp(str + sz - ssz, suffix, ssz) != 0) 672 return 0; 673 674 return 1; 675 } 676 677 678 xs_str *xs_crop_i(xs_str *str, int start, int end) 679 /* crops the string to be only from start to end */ 680 { 681 int sz = strlen(str); 682 683 if (end <= 0) 684 end = sz + end; 685 686 /* crop from the top */ 687 if (end >= 0 && end < sz) 688 str[end] = '\0'; 689 690 /* crop from the bottom */ 691 str = xs_collapse(str, 0, start); 692 693 return str; 694 } 695 696 697 xs_str *xs_lstrip_chars_i(xs_str *str, const char *chars) 698 /* strips all chars from the start of str */ 699 { 700 int n = strspn(str, chars);; 701 702 if (n) 703 str = xs_collapse(str, 0, n); 704 705 return str; 706 } 707 708 709 xs_str *xs_rstrip_chars_i(xs_str *str, const char *chars) 710 /* strips all chars from the end of str */ 711 { 712 int n; 713 714 for (n = strlen(str); n > 0 && strchr(chars, str[n - 1]); n--); 715 str[n] = '\0'; 716 717 return str; 718 } 719 720 721 xs_str *xs_strip_chars_i(xs_str *str, const char *chars) 722 /* strips the string of chars from the start and the end */ 723 { 724 return xs_lstrip_chars_i(xs_rstrip_chars_i(str, chars), chars); 725 } 726 727 728 xs_str *xs_tolower_i(xs_str *str) 729 /* convert to lowercase */ 730 { 731 XS_ASSERT_TYPE(str, XSTYPE_STRING); 732 733 int n; 734 735 for (n = 0; str[n]; n++) 736 str[n] = tolower(str[n]); 737 738 return str; 739 } 740 741 742 /** lists **/ 743 744 xs_list *xs_list_new(void) 745 /* creates a new list */ 746 { 747 int sz = 1 + _XS_TYPE_SIZE + 1; 748 xs_list *l = xs_realloc(NULL, sz); 749 memset(l, '\0', sz); 750 751 l[0] = XSTYPE_LIST; 752 _xs_put_size(l, sz); 753 754 return l; 755 } 756 757 758 xs_list *_xs_list_write_litem(xs_list *list, int offset, const char *mem, int dsz) 759 /* writes a list item */ 760 { 761 XS_ASSERT_TYPE(list, XSTYPE_LIST); 762 763 if (mem == NULL) { 764 mem = xs_stock(XSTYPE_NULL); 765 dsz = xs_size(mem); 766 } 767 768 list = xs_expand(list, offset, dsz + 1); 769 770 list[offset] = XSTYPE_LITEM; 771 memcpy(list + offset + 1, mem, dsz); 772 773 return list; 774 } 775 776 777 xs_list *xs_list_append_m(xs_list *list, const char *mem, int dsz) 778 /* adds a memory block to the list */ 779 { 780 XS_ASSERT_TYPE(list, XSTYPE_LIST); 781 782 return _xs_list_write_litem(list, xs_size(list) - 1, mem, dsz); 783 } 784 785 786 xs_list *_xs_list_append(xs_list *list, const xs_val *vals[]) 787 /* adds several values to the list */ 788 { 789 /* special case: if the first argument is NULL, just insert it */ 790 if (*vals == NULL) 791 return xs_list_append_m(list, NULL, 0); 792 793 while (*vals) { 794 list = xs_list_append_m(list, *vals, xs_size(*vals)); 795 vals++; 796 } 797 798 return list; 799 } 800 801 xs_list *xs_list_append_nstr(xs_list *list, const char *str, int n) 802 { 803 list = xs_list_append_m(list, str, n + 1); 804 list[xs_size(list) - 2] = '\0'; 805 return list; 806 } 807 808 809 int xs_list_iter(xs_list **list, const xs_val **value) 810 /* iterates a list value */ 811 { 812 int goon = 1; 813 814 xs_val *p = *list; 815 816 /* skip the start of the list */ 817 if (xs_type(p) == XSTYPE_LIST) 818 p += 1 + _XS_TYPE_SIZE; 819 820 /* an element? */ 821 if (xs_type(p) == XSTYPE_LITEM) { 822 p++; 823 824 *value = p; 825 826 p += xs_size(*value); 827 } 828 else { 829 /* end of list */ 830 goon = 0; 831 } 832 833 /* store back the pointer */ 834 *list = p; 835 836 return goon; 837 } 838 839 840 int xs_list_next(const xs_list *list, const xs_val **value, int *ctxt) 841 /* iterates a list, with context */ 842 { 843 if (xs_type(list) != XSTYPE_LIST) 844 return 0; 845 846 int goon = 1; 847 848 const char *p = list; 849 850 /* skip the start of the list */ 851 if (*ctxt == 0) 852 *ctxt = 1 + _XS_TYPE_SIZE; 853 854 p += *ctxt; 855 856 /* an element? */ 857 if (xs_type(p) == XSTYPE_LITEM) { 858 p++; 859 860 *value = p; 861 862 p += xs_size(*value); 863 } 864 else { 865 /* end of list */ 866 goon = 0; 867 } 868 869 /* update the context */ 870 *ctxt = p - list; 871 872 return goon; 873 } 874 875 876 int xs_list_len(const xs_list *list) 877 /* returns the number of elements in the list */ 878 { 879 XS_ASSERT_TYPE_NULL(list, XSTYPE_LIST); 880 881 int c = 0; 882 const xs_val *v; 883 884 xs_list_foreach(list, v) 885 c++; 886 887 return c; 888 } 889 890 891 const xs_val *xs_list_get(const xs_list *list, int num) 892 /* returns the element #num */ 893 { 894 XS_ASSERT_TYPE(list, XSTYPE_LIST); 895 896 if (num < 0) 897 num = xs_list_len(list) + num; 898 899 int c = 0; 900 const xs_val *v; 901 902 xs_list_foreach(list, v) { 903 if (c == num) 904 return v; 905 906 c++; 907 } 908 909 return NULL; 910 } 911 912 913 xs_list *xs_list_del(xs_list *list, int num) 914 /* deletes element #num */ 915 { 916 XS_ASSERT_TYPE(list, XSTYPE_LIST); 917 918 const xs_val *v; 919 920 if ((v = xs_list_get(list, num)) != NULL) 921 list = xs_collapse(list, v - 1 - list, xs_size(v - 1)); 922 923 return list; 924 } 925 926 927 xs_list *xs_list_insert(xs_list *list, int num, const xs_val *data) 928 /* inserts an element at #num position */ 929 { 930 XS_ASSERT_TYPE(list, XSTYPE_LIST); 931 932 const xs_val *v; 933 int offset; 934 935 if ((v = xs_list_get(list, num)) != NULL) 936 offset = v - list; 937 else 938 offset = xs_size(list); 939 940 return _xs_list_write_litem(list, offset - 1, data, xs_size(data)); 941 } 942 943 944 xs_list *xs_list_set(xs_list *list, int num, const xs_val *data) 945 /* sets the element at #num position */ 946 { 947 XS_ASSERT_TYPE(list, XSTYPE_LIST); 948 949 list = xs_list_del(list, num); 950 list = xs_list_insert(list, num, data); 951 952 return list; 953 } 954 955 956 xs_list *xs_list_dequeue(xs_list *list, xs_val **data, int last) 957 /* gets a copy of the first or last element of a list, shrinking it */ 958 { 959 XS_ASSERT_TYPE(list, XSTYPE_LIST); 960 961 int ct = 0; 962 const xs_val *v = NULL; 963 964 if (!last) { 965 /* get the first */ 966 xs_list_next(list, &v, &ct); 967 } 968 else { 969 /* iterate to the end */ 970 while (xs_list_next(list, &v, &ct)); 971 } 972 973 if (v != NULL) { 974 *data = xs_dup(v); 975 976 /* collapse from the address of the element */ 977 list = xs_collapse(list, v - 1 - list, xs_size(v - 1)); 978 } 979 980 return list; 981 } 982 983 984 int xs_list_in(const xs_list *list, const xs_val *val) 985 /* returns the position of val in list or -1 */ 986 { 987 XS_ASSERT_TYPE_NULL(list, XSTYPE_LIST); 988 989 int n = 0; 990 const xs_val *v; 991 int sz = xs_size(val); 992 993 xs_list_foreach(list, v) { 994 if (sz == xs_size(v) && memcmp(val, v, sz) == 0) 995 return n; 996 997 n++; 998 } 999 1000 return -1; 1001 } 1002 1003 1004 xs_str *xs_join(const xs_list *list, const char *sep) 1005 /* joins a list into a string */ 1006 { 1007 XS_ASSERT_TYPE(list, XSTYPE_LIST); 1008 1009 xs_str *s = NULL; 1010 const xs_val *v; 1011 int c = 0; 1012 int offset = 0; 1013 int ssz = strlen(sep); 1014 1015 xs_list_foreach(list, v) { 1016 /* refuse to join non-string values */ 1017 if (xs_type(v) == XSTYPE_STRING) { 1018 int sz; 1019 1020 /* add the separator */ 1021 if (c != 0 && ssz) { 1022 s = xs_realloc(s, offset + ssz); 1023 memcpy(s + offset, sep, ssz); 1024 offset += ssz; 1025 } 1026 1027 /* add the element */ 1028 if ((sz = strlen(v)) > 0) { 1029 s = xs_realloc(s, offset + sz); 1030 memcpy(s + offset, v, sz); 1031 offset += sz; 1032 } 1033 1034 c++; 1035 } 1036 } 1037 1038 /* null-terminate */ 1039 s = xs_realloc(s, _xs_blk_size(offset + 1)); 1040 s[offset] = '\0'; 1041 1042 return s; 1043 } 1044 1045 1046 xs_list *xs_split_n(const char *str, const char *sep, int times) 1047 /* splits a string into a list upto n times */ 1048 { 1049 xs_list *list = xs_list_new(); 1050 1051 if (!xs_is_string(str) || !xs_is_string(sep)) 1052 return list; 1053 1054 int sz = strlen(sep); 1055 char *ss; 1056 1057 while (times > 0 && (ss = strstr(str, sep)) != NULL) { 1058 /* create a new string with this slice and add it to the list */ 1059 xs *s = xs_str_new_sz(str, ss - str); 1060 1061 if (xs_is_string(s)) 1062 list = xs_list_append(list, s); 1063 1064 /* skip past the separator */ 1065 str = ss + sz; 1066 1067 times--; 1068 } 1069 1070 /* add the rest of the string */ 1071 if (xs_is_string(str)) 1072 list = xs_list_append(list, str); 1073 1074 return list; 1075 } 1076 1077 1078 xs_list *xs_list_cat(xs_list *l1, const xs_list *l2) 1079 /* concatenates list l2 to l1 */ 1080 { 1081 XS_ASSERT_TYPE(l1, XSTYPE_LIST); 1082 XS_ASSERT_TYPE(l2, XSTYPE_LIST); 1083 1084 /* inserts at the end of l1 the content of l2 (skipping header and footer) */ 1085 return xs_insert_m(l1, xs_size(l1) - 1, 1086 l2 + 1 + _XS_TYPE_SIZE, xs_size(l2) - (1 + _XS_TYPE_SIZE + 1)); 1087 } 1088 1089 1090 /** keyvals **/ 1091 1092 int xs_keyval_size(const xs_str *key, const xs_val *value) 1093 /* returns the needed size for a keyval */ 1094 { 1095 return 1 + xs_size(key) + xs_size(value); 1096 } 1097 1098 1099 xs_str *xs_keyval_key(const xs_keyval *keyval) 1100 /* returns a pointer to the key of the keyval */ 1101 { 1102 return (xs_str *)&keyval[1]; 1103 } 1104 1105 1106 xs_val *xs_keyval_value(const xs_keyval *keyval) 1107 /* returns a pointer to the value of the keyval */ 1108 { 1109 return (xs_val *)&keyval[1 + xs_size(xs_keyval_key(keyval))]; 1110 } 1111 1112 1113 xs_keyval *xs_keyval_make(xs_keyval *keyval, const xs_str *key, const xs_val *value) 1114 /* builds a keyval into mem (should have enough size) */ 1115 { 1116 keyval[0] = XSTYPE_KEYVAL; 1117 memcpy(xs_keyval_key(keyval), key, xs_size(key)); 1118 memcpy(xs_keyval_value(keyval), value, xs_size(value)); 1119 1120 return keyval; 1121 } 1122 1123 1124 /** dicts **/ 1125 1126 typedef struct { 1127 int value_offset; /* offset to value (from dict start) */ 1128 int next; /* next node in sequential scanning */ 1129 int child[4]; /* child nodes in hashed search */ 1130 char key[]; /* C string key */ 1131 } ditem_hdr; 1132 1133 typedef struct { 1134 int size; /* size of full dict (_XS_TYPE_SIZE) */ 1135 int first; /* first node for sequential scanning */ 1136 int last; /* last node for sequential scanning */ 1137 int root; /* root node for hashed search */ 1138 /* a bunch of ditem_hdr and value follows */ 1139 } dict_hdr; 1140 1141 1142 xs_dict *xs_dict_new(void) 1143 /* creates a new dict */ 1144 { 1145 /* size of dict */ 1146 int sz = 1 + sizeof(dict_hdr); 1147 1148 xs_dict *d = xs_realloc(NULL, sz); 1149 memset(d, '\0', sz); 1150 1151 d[0] = XSTYPE_DICT; 1152 _xs_put_size(d, sz); 1153 1154 return d; 1155 } 1156 1157 static int *_xs_dict_locate(const xs_dict *dict, const char *key, int ksz) 1158 /* locates a ditem */ 1159 { 1160 unsigned int h = xs_hash_func(key, ksz); 1161 1162 /* start from the root */ 1163 dict_hdr *dh = (dict_hdr *)(dict + 1); 1164 int *off = &dh->root; 1165 1166 while (*off) { 1167 /* pointer to ditem */ 1168 ditem_hdr *di = (ditem_hdr *)(dict + *off); 1169 1170 /* pointer to the key */ 1171 const char *d_key = di->key; 1172 1173 if (strcmp(key, d_key) == 0) 1174 break; 1175 1176 off = &di->child[h >> 30]; 1177 h <<= 2; 1178 } 1179 1180 return off; 1181 } 1182 1183 xs_dict *_xs_dict_ensure(xs_dict *dict, const xs_str *key, int klen, int vsz, int *offset) 1184 { 1185 if (xs_type(dict) == XSTYPE_DICT) { 1186 int *o = _xs_dict_locate(dict, key, klen); 1187 int end = xs_size(dict); 1188 1189 if (!*o) { 1190 /* ditem does not exist yet: append to the end */ 1191 *o = end; 1192 1193 int dsz = sizeof(ditem_hdr) + klen + 1 + vsz; 1194 1195 /* open room in the dict for the full ditem */ 1196 dict = xs_expand(dict, end, dsz); 1197 1198 dict_hdr *dh = (dict_hdr *)(dict + 1); 1199 1200 /* build the ditem */ 1201 ditem_hdr *di = (ditem_hdr *)(dict + end); 1202 memset(di, '\0', dsz); 1203 1204 /* set the offset to the value */ 1205 di->value_offset = end + sizeof(ditem_hdr) + klen + 1; 1206 1207 /* copy the key */ 1208 memcpy(di->key, key, klen); 1209 di->key[klen] = '\0'; 1210 1211 /* chain to the sequential list */ 1212 if (dh->first == 0) 1213 dh->first = end; 1214 else { 1215 /* chain this new element to the last one */ 1216 ditem_hdr *dil = (ditem_hdr *)(dict + dh->last); 1217 dil->next = end; 1218 } 1219 1220 dh->last = end; 1221 1222 *offset = di->value_offset; 1223 } 1224 else { 1225 /* ditem already exists */ 1226 ditem_hdr *di = (ditem_hdr *)(dict + *o); 1227 1228 /* get pointer to the value offset */ 1229 int *i = &di->value_offset; 1230 1231 /* deleted? recover offset */ 1232 if (*i < 0) 1233 *i *= -1; 1234 1235 /* get old value */ 1236 xs_val *o_value = dict + *i; 1237 1238 /* will new value fit over the old one? */ 1239 if (vsz > xs_size(o_value)) { 1240 /* not enough room: new value will live at the end of the dict */ 1241 /* (old value is leaked inside the dict) */ 1242 *i = end; 1243 *offset = *i; 1244 1245 dict = xs_expand(dict, end, vsz); 1246 } else 1247 *offset = *i; 1248 } 1249 } 1250 else { 1251 *offset = -1; 1252 } 1253 1254 return dict; 1255 } 1256 1257 xs_dict *xs_dict_set_fmt(xs_dict *dict, const xs_str *key, const char *fmt, ...) 1258 { 1259 if (xs_type(dict) == XSTYPE_DICT) { 1260 int o; 1261 int vsz; 1262 va_list ap; 1263 1264 va_start(ap, fmt); 1265 vsz = vsnprintf(NULL, 0, fmt, ap); 1266 va_end(ap); 1267 1268 if (vsz++ < 0) 1269 return dict; 1270 1271 dict = _xs_dict_ensure(dict, key, strlen(key), vsz, &o); 1272 1273 va_start(ap, fmt); 1274 vsnprintf(dict + o, vsz, fmt, ap); 1275 va_end(ap); 1276 } 1277 1278 return dict; 1279 } 1280 1281 xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *value) 1282 /* sets a key/value pair */ 1283 { 1284 if (value == NULL) 1285 value = xs_stock(XSTYPE_NULL); 1286 1287 if (xs_type(dict) == XSTYPE_DICT) { 1288 int vsz = xs_size(value); 1289 int o; 1290 dict = _xs_dict_ensure(dict, key, strlen(key), vsz, &o); 1291 memcpy(dict + o, value, vsz); 1292 } 1293 1294 return dict; 1295 } 1296 1297 xs_dict *xs_dict_set_strnn(xs_dict *dict, const void *key, int klen, const void *val, int vlen) 1298 /* sets a key/value pair */ 1299 { 1300 if (xs_type(dict) == XSTYPE_DICT) { 1301 int o; 1302 dict = _xs_dict_ensure(dict, key, klen, vlen + 1, &o); 1303 memcpy(dict + o, val, vlen); 1304 *(dict + o + vlen) = '\0'; 1305 } 1306 1307 return dict; 1308 } 1309 1310 xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value) 1311 /* just an alias (for this implementation it's the same) */ 1312 { 1313 return xs_dict_set(dict, key, value); 1314 } 1315 1316 1317 xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value) 1318 /* just an alias (for this implementation it's the same) */ 1319 { 1320 return xs_dict_set(dict, key, value); 1321 } 1322 1323 1324 xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key) 1325 /* deletes a key/value pair */ 1326 { 1327 if (xs_type(dict) == XSTYPE_DICT) { 1328 int *o = _xs_dict_locate(dict, key, strlen(key)); 1329 1330 if (*o) { 1331 /* found ditem */ 1332 ditem_hdr *di = (ditem_hdr *)(dict + *o); 1333 1334 /* deleted ditems have a negative value offset */ 1335 di->value_offset *= -1; 1336 } 1337 } 1338 1339 return dict; 1340 } 1341 1342 1343 const xs_val *xs_dict_get(const xs_dict *dict, const xs_str *key) 1344 /* gets a value by key, or NULL */ 1345 { 1346 if (xs_type(dict) == XSTYPE_DICT) { 1347 int *o = _xs_dict_locate(dict, key, strlen(key)); 1348 1349 if (*o) { 1350 /* found ditem */ 1351 ditem_hdr *di = (ditem_hdr *)(dict + *o); 1352 1353 if (di->value_offset > 0) 1354 return dict + di->value_offset; 1355 } 1356 } 1357 1358 return NULL; 1359 } 1360 1361 1362 int xs_dict_next(const xs_dict *dict, const xs_str **key, const xs_val **value, int *ctxt) 1363 /* dict iterator, with context */ 1364 { 1365 if (xs_type(dict) != XSTYPE_DICT) 1366 return 0; 1367 1368 if (*ctxt == 0) { 1369 /* at the beginning: get the first sequential item */ 1370 const dict_hdr *dh = (dict_hdr *)(dict + 1); 1371 *ctxt = dh->first; 1372 } 1373 1374 *value = NULL; 1375 1376 while (*value == NULL && *ctxt > 0) { 1377 const ditem_hdr *di = (ditem_hdr *)(dict + *ctxt); 1378 1379 /* get value */ 1380 if (di->value_offset > 0) { 1381 *value = (xs_val *)(dict + di->value_offset); 1382 1383 /* get key */ 1384 *key = (xs_str *)&di->key; 1385 } 1386 1387 /* get offset to next ditem */ 1388 *ctxt = di->next ? di->next : -1; 1389 } 1390 1391 return *value != NULL; 1392 } 1393 1394 1395 xs_dict *xs_dict_gc(const xs_dict *dict) 1396 /* creates a copy of dict, but garbage-collected */ 1397 { 1398 xs_dict *nd = xs_dict_new(); 1399 const xs_str *k; 1400 const xs_val *v; 1401 1402 xs_dict_foreach(dict, k, v) { 1403 if (xs_type(v) == XSTYPE_DICT) { 1404 xs *sd = xs_dict_gc(v); 1405 nd = xs_dict_set(nd, k, sd); 1406 } 1407 else 1408 nd = xs_dict_set(nd, k, v); 1409 } 1410 1411 return nd; 1412 } 1413 1414 1415 const xs_val *xs_dict_get_path_sep(const xs_dict *dict, const char *path, const char *sep) 1416 /* gets a value from dict given a path separated by sep */ 1417 { 1418 /* split by the separator */ 1419 xs *l = xs_split_n(path, sep, 1); 1420 1421 /* only one part? just get */ 1422 if (xs_list_len(l) == 1) 1423 return xs_dict_get(dict, path); 1424 1425 const char *prefix = xs_list_get(l, 0); 1426 const char *rest = xs_list_get(l, 1); 1427 const xs_dict *sd = xs_dict_get(dict, prefix); 1428 1429 if (xs_type(sd) == XSTYPE_DICT) 1430 return xs_dict_get_path_sep(sd, rest, sep); 1431 1432 return NULL; 1433 } 1434 1435 1436 xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *value, const char *sep) 1437 /* sets a value into dict given a path separated by sep; 1438 intermediate dicts are created if needed */ 1439 { 1440 /* split by the separator */ 1441 xs *l = xs_split_n(path, sep, 1); 1442 1443 /* only one part? just set */ 1444 if (xs_list_len(l) == 1) 1445 return xs_dict_set(dict, path, value); 1446 1447 const char *prefix = xs_list_get(l, 0); 1448 const char *rest = xs_list_get(l, 1); 1449 1450 xs *nd = NULL; 1451 1452 /* does the first part of path exist? */ 1453 const xs_dict *cd = xs_dict_get(dict, prefix); 1454 1455 if (xs_type(cd) == XSTYPE_DICT) 1456 nd = xs_dup(cd); 1457 else 1458 nd = xs_dict_new(); 1459 1460 /* move down the path */ 1461 nd = xs_dict_set_path_sep(nd, rest, value, sep); 1462 1463 /* set */ 1464 return xs_dict_set(dict, prefix, nd); 1465 } 1466 1467 1468 /** other values **/ 1469 1470 xs_val *xs_val_new(xstype t) 1471 /* adds a new special value */ 1472 { 1473 xs_val *v = xs_realloc(NULL, _xs_blk_size(1)); 1474 1475 v[0] = t; 1476 1477 return v; 1478 } 1479 1480 1481 /** numbers */ 1482 1483 xs_number *xs_number_new(double f) 1484 /* adds a new number value */ 1485 { 1486 xs_number *v; 1487 char tmp[64]; 1488 1489 snprintf(tmp, sizeof(tmp), "%.15lf", f); 1490 1491 /* strip useless zeros */ 1492 if (strchr(tmp, '.') != NULL) { 1493 char *ptr; 1494 1495 for (ptr = tmp + strlen(tmp) - 1; *ptr == '0'; ptr--); 1496 1497 if (*ptr != '.') 1498 ptr++; 1499 1500 *ptr = '\0'; 1501 } 1502 1503 /* alloc for the marker and the full string */ 1504 v = xs_realloc(NULL, _xs_blk_size(1 + xs_size(tmp))); 1505 1506 v[0] = XSTYPE_NUMBER; 1507 memcpy(&v[1], tmp, xs_size(tmp)); 1508 1509 return v; 1510 } 1511 1512 1513 double xs_number_get(const xs_number *v) 1514 /* gets the number as a double */ 1515 { 1516 double f = 0.0; 1517 1518 if (xs_type(v) == XSTYPE_NUMBER) 1519 f = atof(&v[1]); 1520 else 1521 if (xs_type(v) == XSTYPE_STRING) 1522 f = atof(v); 1523 1524 return f; 1525 } 1526 1527 1528 const char *xs_number_str(const xs_number *v) 1529 /* gets the number as a string */ 1530 { 1531 const char *p = NULL; 1532 1533 if (xs_type(v) == XSTYPE_NUMBER) 1534 p = &v[1]; 1535 1536 return p; 1537 } 1538 1539 1540 /** raw data blocks **/ 1541 1542 xs_data *xs_data_new(const void *data, int size) 1543 /* returns a new raw data value */ 1544 { 1545 xs_data *v; 1546 1547 /* add the overhead (data type + size) */ 1548 int total_size = size + 1 + _XS_TYPE_SIZE; 1549 1550 v = xs_realloc(NULL, _xs_blk_size(total_size)); 1551 v[0] = XSTYPE_DATA; 1552 1553 _xs_put_size(v, total_size); 1554 1555 memcpy(&v[1 + _XS_TYPE_SIZE], data, size); 1556 1557 return v; 1558 } 1559 1560 1561 int xs_data_size(const xs_data *value) 1562 /* returns the size of the data stored inside value */ 1563 { 1564 return _xs_get_size(value) - (1 + _XS_TYPE_SIZE); 1565 } 1566 1567 1568 void xs_data_get(void *data, const xs_data *value) 1569 /* copies the raw data stored inside value into data */ 1570 { 1571 memcpy(data, &value[1 + _XS_TYPE_SIZE], xs_data_size(value)); 1572 } 1573 1574 1575 void *xs_memmem(const char *haystack, int h_size, const char *needle, int n_size) 1576 /* clone of memmem */ 1577 { 1578 char *p, *r = NULL; 1579 int offset = 0; 1580 1581 while (!r && h_size - offset > n_size && 1582 (p = memchr(haystack + offset, *needle, h_size - offset))) { 1583 if (memcmp(p, needle, n_size) == 0) 1584 r = p; 1585 else 1586 offset = p - haystack + 1; 1587 } 1588 1589 return r; 1590 } 1591 1592 1593 unsigned int xs_hash_func(const char *data, int size) 1594 /* a general purpose hashing function */ 1595 { 1596 unsigned int hash = 0x666; 1597 1598 for (int n = 0; n < size; n++) { 1599 hash ^= (unsigned char)data[n]; 1600 hash *= 111111111; 1601 } 1602 1603 return hash ^ hash >> 16; 1604 } 1605 1606 1607 uint64_t xs_hash64_func(const char *data, int size) 1608 /* a general purpose hashing function (64 bit) */ 1609 { 1610 uint64_t hash = 0x100; 1611 1612 for (int n = 0; n < size; n++) { 1613 hash ^= (unsigned char)data[n]; 1614 hash *= 1111111111111111111; 1615 } 1616 1617 return hash; 1618 } 1619 1620 1621 #endif /* XS_IMPLEMENTATION */ 1622 1623 #endif /* _XS_H */