18abd06a7SGlenn Strauss #include "first.h" 28abd06a7SGlenn Strauss 322e8b456SStefan Bühler #include "array.h" 422e8b456SStefan Bühler #include "buffer.h" 522e8b456SStefan Bühler 6bcdc6a3bSJan Kneschke #include <string.h> 7bcdc6a3bSJan Kneschke #include <stdlib.h> 8bcdc6a3bSJan Kneschke #include <limits.h> 9bcdc6a3bSJan Kneschke 10b2991c68SGlenn Strauss __attribute_cold__ 1124680a91SGlenn Strauss static void array_extend(array * const a, uint32_t n) { 1224680a91SGlenn Strauss a->size += n; 13b2991c68SGlenn Strauss a->data = realloc(a->data, sizeof(*a->data) * a->size); 14a762402dSGlenn Strauss a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size); 15b2991c68SGlenn Strauss force_assert(a->data); 16a762402dSGlenn Strauss force_assert(a->sorted); 17b2991c68SGlenn Strauss memset(a->data+a->used, 0, (a->size-a->used)*sizeof(*a->data)); 18b2991c68SGlenn Strauss } 19224bf545SStefan Bühler 2024680a91SGlenn Strauss array *array_init(uint32_t n) { 21bcdc6a3bSJan Kneschke array *a; 22bcdc6a3bSJan Kneschke 23bcdc6a3bSJan Kneschke a = calloc(1, sizeof(*a)); 2407dd0bd0SStefan Bühler force_assert(a); 2524680a91SGlenn Strauss if (n) array_extend(a, n); 26bcdc6a3bSJan Kneschke 27bcdc6a3bSJan Kneschke return a; 28bcdc6a3bSJan Kneschke } 29bcdc6a3bSJan Kneschke 30c2238256SGlenn Strauss void array_free_data(array * const a) { 31a762402dSGlenn Strauss if (a->sorted) free(a->sorted); 32b2991c68SGlenn Strauss data_unset ** const data = a->data; 33b2991c68SGlenn Strauss const uint32_t sz = a->size; 34b2991c68SGlenn Strauss for (uint32_t i = 0; i < sz; ++i) { 35b2991c68SGlenn Strauss if (data[i]) data[i]->fn->free(data[i]); 36bcdc6a3bSJan Kneschke } 37c2238256SGlenn Strauss free(data); 38f24e6d69SGlenn Strauss a->data = NULL; 39f24e6d69SGlenn Strauss a->sorted = NULL; 40f24e6d69SGlenn Strauss a->used = 0; 41f24e6d69SGlenn Strauss a->size = 0; 42c2238256SGlenn Strauss } 43bcdc6a3bSJan Kneschke 44c2238256SGlenn Strauss void array_copy_array(array * const dst, const array * const src) { 45c2238256SGlenn Strauss array_free_data(dst); 46c2238256SGlenn Strauss if (0 == src->size) return; 47c2238256SGlenn Strauss 48*fefdf7f0SGlenn Strauss array_extend(dst, src->size); 49c2238256SGlenn Strauss for (uint32_t i = 0; i < src->used; ++i) { 50*fefdf7f0SGlenn Strauss array_insert_unique(dst, src->data[i]->fn->copy(src->data[i])); 51c2238256SGlenn Strauss } 52c2238256SGlenn Strauss } 53c2238256SGlenn Strauss 54c2238256SGlenn Strauss void array_free(array * const a) { 55c2238256SGlenn Strauss if (!a) return; 56c2238256SGlenn Strauss array_free_data(a); 57bcdc6a3bSJan Kneschke free(a); 58bcdc6a3bSJan Kneschke } 59bcdc6a3bSJan Kneschke 60b2991c68SGlenn Strauss void array_reset_data_strings(array * const a) { 61062089ffSGlenn Strauss if (!a) return; 62062089ffSGlenn Strauss 63b2991c68SGlenn Strauss data_string ** const data = (data_string **)a->data; 64b2991c68SGlenn Strauss const uint32_t used = a->used; 65b2991c68SGlenn Strauss a->used = 0; 66b2991c68SGlenn Strauss for (uint32_t i = 0; i < used; ++i) { 67b2991c68SGlenn Strauss data_string * const ds = data[i]; 68062089ffSGlenn Strauss /*force_assert(ds->type == TYPE_STRING);*/ 69b600b75fSGlenn Strauss buffer_reset(&ds->key); 70b600b75fSGlenn Strauss buffer_reset(&ds->value); 71b2991c68SGlenn Strauss } 72062089ffSGlenn Strauss } 73062089ffSGlenn Strauss 74b2991c68SGlenn Strauss #if 0 /*(unused; see array_extract_element_klen())*/ 75b2991c68SGlenn Strauss data_unset *array_pop(array * const a) { 768073d5feSJan Kneschke data_unset *du; 778073d5feSJan Kneschke 7807dd0bd0SStefan Bühler force_assert(a->used != 0); 798073d5feSJan Kneschke 808073d5feSJan Kneschke a->used --; 818073d5feSJan Kneschke du = a->data[a->used]; 82e3dc34d1SGlenn Strauss force_assert(a->sorted[a->used] == du); /* only works on "simple" lists */ 838073d5feSJan Kneschke a->data[a->used] = NULL; 848073d5feSJan Kneschke 858073d5feSJan Kneschke return du; 868073d5feSJan Kneschke } 87b2991c68SGlenn Strauss #endif 888073d5feSJan Kneschke 89ca059d58SGlenn Strauss __attribute_pure__ 9068ec5ad6SGlenn Strauss static int array_caseless_compare(const char * const a, const char * const b, const uint32_t len) { 9168ec5ad6SGlenn Strauss for (uint32_t i = 0; i < len; ++i) { 92ca059d58SGlenn Strauss unsigned int ca = ((unsigned char *)a)[i]; 93ca059d58SGlenn Strauss unsigned int cb = ((unsigned char *)b)[i]; 94ca059d58SGlenn Strauss if (ca == cb) continue; 95ca059d58SGlenn Strauss 96ca059d58SGlenn Strauss /* always lowercase for transitive results */ 97c58b95f2SGlenn Strauss if (light_isupper(ca)) ca |= 0x20; 98c58b95f2SGlenn Strauss if (light_isupper(cb)) cb |= 0x20; 99ca059d58SGlenn Strauss 100ca059d58SGlenn Strauss if (ca == cb) continue; 101ca059d58SGlenn Strauss return (int)(ca - cb); 102ca059d58SGlenn Strauss } 103ca059d58SGlenn Strauss return 0; 104ca059d58SGlenn Strauss } 105ca059d58SGlenn Strauss 106ca059d58SGlenn Strauss __attribute_pure__ 10768ec5ad6SGlenn Strauss static int array_keycmp(const char * const a, const uint32_t alen, const char * const b, const uint32_t blen) { 108ca059d58SGlenn Strauss return alen < blen ? -1 : alen > blen ? 1 : array_caseless_compare(a, b, blen); 109758174ecSGlenn Strauss } 110758174ecSGlenn Strauss 1112e0676fdSGlenn Strauss __attribute_cold__ 1122e0676fdSGlenn Strauss __attribute_pure__ 1132e0676fdSGlenn Strauss static int array_keycmpb(const char * const k, const uint32_t klen, const buffer * const b) { 1142e0676fdSGlenn Strauss /* key is non-empty (0==b->used), though possibly blank (1==b->used) 1152e0676fdSGlenn Strauss * if inserted into key-value array */ 1162e0676fdSGlenn Strauss /*force_assert(b && b->used);*/ 1172e0676fdSGlenn Strauss return array_keycmp(k, klen, b->ptr, b->used-1); 1182e0676fdSGlenn Strauss /*return array_keycmp(k, klen, CONST_BUF_LEN(b));*/ 1192e0676fdSGlenn Strauss } 1202e0676fdSGlenn Strauss 1212e0676fdSGlenn Strauss /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] 1222e0676fdSGlenn Strauss * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] 1232e0676fdSGlenn Strauss * where the key needs to be inserted (-1 to avoid -0) 1242e0676fdSGlenn Strauss */ 1252e0676fdSGlenn Strauss __attribute_hot__ 1262e0676fdSGlenn Strauss __attribute_pure__ 1272e0676fdSGlenn Strauss static int32_t array_get_index_ext(const array * const a, const int ext, const char * const k, const uint32_t klen) { 1282e0676fdSGlenn Strauss /* invariant: [lower-1] < probe < [upper] 1292e0676fdSGlenn Strauss * invariant: 0 <= lower <= upper <= a->used 1302e0676fdSGlenn Strauss */ 1312e0676fdSGlenn Strauss uint32_t lower = 0, upper = a->used; 1322e0676fdSGlenn Strauss while (lower != upper) { 1332e0676fdSGlenn Strauss const uint32_t probe = (lower + upper) / 2; 1342e0676fdSGlenn Strauss const int x = ((data_string *)a->sorted[probe])->ext; 1352e0676fdSGlenn Strauss /* (compare strings only if ext is 0 for both)*/ 1362e0676fdSGlenn Strauss const int e = (ext|x) 1372e0676fdSGlenn Strauss ? ext 1382e0676fdSGlenn Strauss : array_keycmpb(k, klen, &a->sorted[probe]->key); 1392e0676fdSGlenn Strauss if (e < x) /* e < [probe] */ 1402e0676fdSGlenn Strauss upper = probe; /* still: lower <= upper */ 1412e0676fdSGlenn Strauss else if (e > x) /* e > [probe] */ 1422e0676fdSGlenn Strauss lower = probe + 1; /* still: lower <= upper */ 1432e0676fdSGlenn Strauss else /*(e == x)*/ /* found */ 1442e0676fdSGlenn Strauss return (int32_t)probe; 1452e0676fdSGlenn Strauss } 1462e0676fdSGlenn Strauss /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 1472e0676fdSGlenn Strauss return -(int)lower - 1; 1482e0676fdSGlenn Strauss } 1492e0676fdSGlenn Strauss 1502e0676fdSGlenn Strauss data_unset *array_get_element_klen_ext(const array * const a, const int ext, const char *key, const uint32_t klen) { 1512e0676fdSGlenn Strauss const int32_t ipos = array_get_index_ext(a, ext, key, klen); 1522e0676fdSGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL; 1532e0676fdSGlenn Strauss } 1542e0676fdSGlenn Strauss 155e3dc34d1SGlenn Strauss /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] 156a762402dSGlenn Strauss * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] 157a762402dSGlenn Strauss * where the key needs to be inserted (-1 to avoid -0) 158224bf545SStefan Bühler */ 159b2991c68SGlenn Strauss __attribute_hot__ 160b2991c68SGlenn Strauss __attribute_pure__ 16168ec5ad6SGlenn Strauss static int32_t array_get_index(const array * const a, const char * const k, const uint32_t klen) { 162b2991c68SGlenn Strauss /* invariant: [lower-1] < probe < [upper] 163b2991c68SGlenn Strauss * invariant: 0 <= lower <= upper <= a->used 164224bf545SStefan Bühler */ 165b2991c68SGlenn Strauss uint32_t lower = 0, upper = a->used; 166224bf545SStefan Bühler while (lower != upper) { 167b2991c68SGlenn Strauss uint32_t probe = (lower + upper) / 2; 168e3dc34d1SGlenn Strauss const buffer * const b = &a->sorted[probe]->key; 16961785d86SGlenn Strauss /* key is non-empty (0==b->used), though possibly blank (1==b->used), 17061785d86SGlenn Strauss * if inserted into key-value array */ 17161785d86SGlenn Strauss /*force_assert(b && b->used);*/ 17261785d86SGlenn Strauss int cmp = array_keycmp(k, klen, b->ptr, b->used-1); 17361785d86SGlenn Strauss /*int cmp = array_keycmp(k, klen, CONST_BUF_LEN(b));*/ 174b2991c68SGlenn Strauss if (cmp < 0) /* key < [probe] */ 175224bf545SStefan Bühler upper = probe; /* still: lower <= upper */ 176b2991c68SGlenn Strauss else if (cmp > 0) /* key > [probe] */ 177224bf545SStefan Bühler lower = probe + 1; /* still: lower <= upper */ 178b2991c68SGlenn Strauss else /*(cmp == 0)*/ /* found */ 179b2991c68SGlenn Strauss return (int32_t)probe; 180bcdc6a3bSJan Kneschke } 181224bf545SStefan Bühler /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 182b2991c68SGlenn Strauss return -(int)lower - 1; 183bcdc6a3bSJan Kneschke } 184bcdc6a3bSJan Kneschke 185b2991c68SGlenn Strauss __attribute_hot__ 18668ec5ad6SGlenn Strauss data_unset *array_get_element_klen(const array * const a, const char *key, const uint32_t klen) { 18783535bbeSGlenn Strauss const int32_t ipos = array_get_index(a, key, klen); 188e3dc34d1SGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL; 18983535bbeSGlenn Strauss } 19083535bbeSGlenn Strauss 19183535bbeSGlenn Strauss /* non-const (data_config *) for configparser.y (not array_get_element_klen())*/ 19268ec5ad6SGlenn Strauss data_unset *array_get_data_unset(const array * const a, const char *key, const uint32_t klen) { 193b2991c68SGlenn Strauss const int32_t ipos = array_get_index(a, key, klen); 194e3dc34d1SGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL; 195bcdc6a3bSJan Kneschke } 196bcdc6a3bSJan Kneschke 19768ec5ad6SGlenn Strauss data_unset *array_extract_element_klen(array * const a, const char *key, const uint32_t klen) { 198b2991c68SGlenn Strauss const int32_t ipos = array_get_index(a, key, klen); 199b2991c68SGlenn Strauss if (ipos < 0) return NULL; 200bcdc6a3bSJan Kneschke 201e3dc34d1SGlenn Strauss /* remove entry from a->sorted: move everything after pos one step left */ 202e3dc34d1SGlenn Strauss data_unset * const entry = a->sorted[ipos]; 203c9f1b612SGlenn Strauss const uint32_t last_ndx = --a->used; 204e3dc34d1SGlenn Strauss if (last_ndx != (uint32_t)ipos) { 205e3dc34d1SGlenn Strauss data_unset ** const d = a->sorted + ipos; 206e3dc34d1SGlenn Strauss memmove(d, d+1, (last_ndx - (uint32_t)ipos) * sizeof(*d)); 207c9f1b612SGlenn Strauss } 208a762402dSGlenn Strauss 209e3dc34d1SGlenn Strauss if (entry != a->data[last_ndx]) { 210e3dc34d1SGlenn Strauss /* walk a->data[] to find data ptr */ 211e3dc34d1SGlenn Strauss /* (not checking (ndx <= last_ndx) since entry must be in a->data[]) */ 212e3dc34d1SGlenn Strauss uint32_t ndx = 0; 213e3dc34d1SGlenn Strauss while (entry != a->data[ndx]) ++ndx; 214e3dc34d1SGlenn Strauss a->data[ndx] = a->data[last_ndx]; /* swap with last element */ 215a762402dSGlenn Strauss } 21668e4a416SStefan Bühler a->data[last_ndx] = NULL; 21768e4a416SStefan Bühler return entry; 21868e4a416SStefan Bühler } 21968e4a416SStefan Bühler 220b2991c68SGlenn Strauss static data_unset *array_get_unused_element(array * const a, const data_type_t t) { 221c752d469SGlenn Strauss /* After initial startup and config, most array usage is of homogeneous types 222b2991c68SGlenn Strauss * and arrays are cleared once per request, so check only the first unused 223b2991c68SGlenn Strauss * element to see if it can be reused */ 224b2991c68SGlenn Strauss #if 1 225b2991c68SGlenn Strauss data_unset * const du = (a->used < a->size) ? a->data[a->used] : NULL; 226b2991c68SGlenn Strauss if (NULL != du && du->type == t) { 227b2991c68SGlenn Strauss a->data[a->used] = NULL;/* make empty slot at a->used for next insert */ 228b2991c68SGlenn Strauss return du; 229b2991c68SGlenn Strauss } 230b2991c68SGlenn Strauss return NULL; 231b2991c68SGlenn Strauss #else 232b2991c68SGlenn Strauss data_unset ** const data = a->data; 233b2991c68SGlenn Strauss for (uint32_t i = a->used, sz = a->size; i < sz; ++i) { 234b2991c68SGlenn Strauss if (data[i] && data[i]->type == t) { 235b2991c68SGlenn Strauss data_unset * const ds = data[i]; 236bcdc6a3bSJan Kneschke 23712f375f3SStefan Bühler /* make empty slot at a->used for next insert */ 238b2991c68SGlenn Strauss data[i] = data[a->used]; 239b2991c68SGlenn Strauss data[a->used] = NULL; 240bcdc6a3bSJan Kneschke 241bcdc6a3bSJan Kneschke return ds; 242bcdc6a3bSJan Kneschke } 24312f375f3SStefan Bühler } 24412f375f3SStefan Bühler 24512f375f3SStefan Bühler return NULL; 246b2991c68SGlenn Strauss #endif 24712f375f3SStefan Bühler } 248bcdc6a3bSJan Kneschke 2492e0676fdSGlenn Strauss __attribute_hot__ 250b2991c68SGlenn Strauss static void array_insert_data_at_pos(array * const a, data_unset * const entry, const uint32_t pos) { 251b2991c68SGlenn Strauss /* This data structure should not be used for nearly so many entries */ 252b2991c68SGlenn Strauss force_assert(a->used + 1 <= INT32_MAX); 253bcdc6a3bSJan Kneschke 254d28bac32SGlenn Strauss if (a->size == a->used) { 25524680a91SGlenn Strauss array_extend(a, 16); 256bcdc6a3bSJan Kneschke } 257bcdc6a3bSJan Kneschke 258b2991c68SGlenn Strauss const uint32_t ndx = a->used++; 259b2991c68SGlenn Strauss data_unset * const prev = a->data[ndx]; 260a762402dSGlenn Strauss a->data[ndx] = entry; 261bcdc6a3bSJan Kneschke 2628d8ae9cbSStefan Bühler /* move everything one step to the right */ 263bcdc6a3bSJan Kneschke if (pos != ndx) { 264e3dc34d1SGlenn Strauss data_unset ** const d = a->sorted + pos; 265e3dc34d1SGlenn Strauss memmove(d+1, d, (ndx - pos) * sizeof(*a->sorted)); 266bcdc6a3bSJan Kneschke } 267e3dc34d1SGlenn Strauss a->sorted[pos] = entry; 268bcdc6a3bSJan Kneschke 269b2991c68SGlenn Strauss if (prev) prev->fn->free(prev); /* free prior data, if any, from slot */ 270b2991c68SGlenn Strauss } 271b2991c68SGlenn Strauss 272b2991c68SGlenn Strauss static data_integer * array_insert_integer_at_pos(array * const a, const uint32_t pos) { 273b2991c68SGlenn Strauss #if 0 /*(not currently used by lighttpd in way that reuse would occur)*/ 274b2991c68SGlenn Strauss data_integer *di = (data_integer *)array_get_unused_element(a,TYPE_INTEGER); 275b2991c68SGlenn Strauss if (NULL == di) di = data_integer_init(); 276b2991c68SGlenn Strauss #else 277b2991c68SGlenn Strauss data_integer * const di = data_integer_init(); 278b2991c68SGlenn Strauss #endif 279b2991c68SGlenn Strauss array_insert_data_at_pos(a, (data_unset *)di, pos); 280b2991c68SGlenn Strauss return di; 281b2991c68SGlenn Strauss } 282b2991c68SGlenn Strauss 2832e0676fdSGlenn Strauss __attribute_hot__ 284b2991c68SGlenn Strauss static data_string * array_insert_string_at_pos(array * const a, const uint32_t pos) { 285b2991c68SGlenn Strauss data_string *ds = (data_string *)array_get_unused_element(a, TYPE_STRING); 286b2991c68SGlenn Strauss if (NULL == ds) ds = data_string_init(); 287b2991c68SGlenn Strauss array_insert_data_at_pos(a, (data_unset *)ds, pos); 288b2991c68SGlenn Strauss return ds; 289b2991c68SGlenn Strauss } 290b2991c68SGlenn Strauss 2912e0676fdSGlenn Strauss __attribute_hot__ 2922e0676fdSGlenn Strauss buffer * array_get_buf_ptr_ext(array * const a, const int ext, const char * const k, const uint32_t klen) { 2932e0676fdSGlenn Strauss int32_t ipos = array_get_index_ext(a, ext, k, klen); 2942e0676fdSGlenn Strauss if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value; 2952e0676fdSGlenn Strauss 2962e0676fdSGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1)); 2972e0676fdSGlenn Strauss ds->ext = ext; 2982e0676fdSGlenn Strauss buffer_copy_string_len(&ds->key, k, klen); 2992e0676fdSGlenn Strauss buffer_clear(&ds->value); 3002e0676fdSGlenn Strauss return &ds->value; 3012e0676fdSGlenn Strauss } 3022e0676fdSGlenn Strauss 30368ec5ad6SGlenn Strauss int * array_get_int_ptr(array * const a, const char * const k, const uint32_t klen) { 304b2991c68SGlenn Strauss int32_t ipos = array_get_index(a, k, klen); 305e3dc34d1SGlenn Strauss if (ipos >= 0) return &((data_integer *)a->sorted[ipos])->value; 306b2991c68SGlenn Strauss 307b2991c68SGlenn Strauss data_integer * const di =array_insert_integer_at_pos(a,(uint32_t)(-ipos-1)); 308ad9b7e00SGlenn Strauss buffer_copy_string_len(&di->key, k, klen); 309db5ff222SGlenn Strauss di->value = 0; 310b2991c68SGlenn Strauss return &di->value; 311b2991c68SGlenn Strauss } 312b2991c68SGlenn Strauss 31368ec5ad6SGlenn Strauss buffer * array_get_buf_ptr(array * const a, const char * const k, const uint32_t klen) { 314b2991c68SGlenn Strauss int32_t ipos = array_get_index(a, k, klen); 315e3dc34d1SGlenn Strauss if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value; 316b2991c68SGlenn Strauss 317b2991c68SGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1)); 318ad9b7e00SGlenn Strauss buffer_copy_string_len(&ds->key, k, klen); 319601c572cSGlenn Strauss buffer_clear(&ds->value); 320601c572cSGlenn Strauss return &ds->value; 321b2991c68SGlenn Strauss } 322b2991c68SGlenn Strauss 32368ec5ad6SGlenn Strauss void array_insert_value(array * const a, const char * const v, const uint32_t vlen) { 324b2991c68SGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, a->used); 325ad9b7e00SGlenn Strauss buffer_clear(&ds->key); 326601c572cSGlenn Strauss buffer_copy_string_len(&ds->value, v, vlen); 327b2991c68SGlenn Strauss } 328b2991c68SGlenn Strauss 329b2991c68SGlenn Strauss /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */ 330b2991c68SGlenn Strauss __attribute_cold__ 331b2991c68SGlenn Strauss static data_unset **array_find_or_insert(array * const a, data_unset * const entry) { 332b2991c68SGlenn Strauss force_assert(NULL != entry); 333b2991c68SGlenn Strauss 334b2991c68SGlenn Strauss /* push value onto end of array if there is no key */ 335ad9b7e00SGlenn Strauss if (buffer_is_empty(&entry->key)) { 336b2991c68SGlenn Strauss array_insert_data_at_pos(a, entry, a->used); 337b2991c68SGlenn Strauss return NULL; 338b2991c68SGlenn Strauss } 339b2991c68SGlenn Strauss 340b2991c68SGlenn Strauss /* try to find the entry */ 341ad9b7e00SGlenn Strauss const int32_t ipos = array_get_index(a, CONST_BUF_LEN(&entry->key)); 342e3dc34d1SGlenn Strauss if (ipos >= 0) return &a->sorted[ipos]; 343b2991c68SGlenn Strauss 344b2991c68SGlenn Strauss array_insert_data_at_pos(a, entry, (uint32_t)(-ipos - 1)); 3458d8ae9cbSStefan Bühler return NULL; 3468d8ae9cbSStefan Bühler } 3478d8ae9cbSStefan Bühler 3488d8ae9cbSStefan Bühler /* replace or insert data (free existing entry) */ 349b2991c68SGlenn Strauss void array_replace(array * const a, data_unset * const entry) { 350e3dc34d1SGlenn Strauss if (NULL == array_find_or_insert(a, entry)) return; 3518d8ae9cbSStefan Bühler 352e3dc34d1SGlenn Strauss /* find the entry (array_find_or_insert() returned non-NULL) */ 353e3dc34d1SGlenn Strauss const int32_t ipos = array_get_index(a, CONST_BUF_LEN(&entry->key)); 354e3dc34d1SGlenn Strauss force_assert(ipos >= 0); 355e3dc34d1SGlenn Strauss data_unset *old = a->sorted[ipos]; 356e3dc34d1SGlenn Strauss force_assert(old != entry); 357e3dc34d1SGlenn Strauss a->sorted[ipos] = entry; 358e3dc34d1SGlenn Strauss 359e3dc34d1SGlenn Strauss uint32_t i = 0; 360e3dc34d1SGlenn Strauss while (i < a->used && a->data[i] != old) ++i; 361e3dc34d1SGlenn Strauss force_assert(i != a->used); 362e3dc34d1SGlenn Strauss a->data[i] = entry; 363e3dc34d1SGlenn Strauss 364e3dc34d1SGlenn Strauss old->fn->free(old); 3658d8ae9cbSStefan Bühler } 3668d8ae9cbSStefan Bühler 367b2991c68SGlenn Strauss void array_insert_unique(array * const a, data_unset * const entry) { 3688d8ae9cbSStefan Bühler data_unset **old; 3698d8ae9cbSStefan Bühler 3708d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) { 3718d8ae9cbSStefan Bühler force_assert((*old)->type == entry->type); 3728c7f1dfbSGlenn Strauss entry->fn->insert_dup(*old, entry); 3738d8ae9cbSStefan Bühler } 374bcdc6a3bSJan Kneschke } 375bcdc6a3bSJan Kneschke 376b2991c68SGlenn Strauss int array_is_vlist(const array * const a) { 377b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 378bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 379ad9b7e00SGlenn Strauss if (!buffer_is_empty(&du->key) || du->type != TYPE_STRING) return 0; 380bd77abe0SGlenn Strauss } 381bd77abe0SGlenn Strauss return 1; 382bd77abe0SGlenn Strauss } 383bd77abe0SGlenn Strauss 384b2991c68SGlenn Strauss int array_is_kvany(const array * const a) { 385b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 386bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 387ad9b7e00SGlenn Strauss if (buffer_is_empty(&du->key)) return 0; 388bd77abe0SGlenn Strauss } 389bd77abe0SGlenn Strauss return 1; 390bd77abe0SGlenn Strauss } 391bd77abe0SGlenn Strauss 392b2991c68SGlenn Strauss int array_is_kvarray(const array * const a) { 393b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 394bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 395ad9b7e00SGlenn Strauss if (buffer_is_empty(&du->key) || du->type != TYPE_ARRAY) return 0; 396bd77abe0SGlenn Strauss } 397bd77abe0SGlenn Strauss return 1; 398bd77abe0SGlenn Strauss } 399bd77abe0SGlenn Strauss 400b2991c68SGlenn Strauss int array_is_kvstring(const array * const a) { 401b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 402bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 403ad9b7e00SGlenn Strauss if (buffer_is_empty(&du->key) || du->type != TYPE_STRING) return 0; 404bd77abe0SGlenn Strauss } 405bd77abe0SGlenn Strauss return 1; 406bd77abe0SGlenn Strauss } 407bd77abe0SGlenn Strauss 408e6741acdSGlenn Strauss /* array_match_*() routines follow very similar pattern, but operate on slightly 409e6741acdSGlenn Strauss * different data: array key/value, prefix/suffix match, case-insensitive or not 410e6741acdSGlenn Strauss * While these could be combined into fewer routines with flags to modify the 411e6741acdSGlenn Strauss * behavior, the interface distinctions are useful to add clarity to the code, 412e6741acdSGlenn Strauss * and the specialized routines run slightly faster */ 413e6741acdSGlenn Strauss 414e6741acdSGlenn Strauss data_unset * 41568ec5ad6SGlenn Strauss array_match_key_prefix_klen (const array * const a, const char * const s, const uint32_t slen) 416e6741acdSGlenn Strauss { 417b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 418ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key; 41968ec5ad6SGlenn Strauss const uint32_t klen = buffer_string_length(key); 420e6741acdSGlenn Strauss if (klen <= slen && 0 == memcmp(s, key->ptr, klen)) 421e6741acdSGlenn Strauss return a->data[i]; 422e6741acdSGlenn Strauss } 423e6741acdSGlenn Strauss return NULL; 424e6741acdSGlenn Strauss } 425e6741acdSGlenn Strauss 426e6741acdSGlenn Strauss data_unset * 42768ec5ad6SGlenn Strauss array_match_key_prefix_nc_klen (const array * const a, const char * const s, const uint32_t slen) 428e6741acdSGlenn Strauss { 429b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 430ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key; 43168ec5ad6SGlenn Strauss const uint32_t klen = buffer_string_length(key); 432e20b5318SGlenn Strauss if (klen <= slen && buffer_eq_icase_ssn(s, key->ptr, klen)) 433e6741acdSGlenn Strauss return a->data[i]; 434e6741acdSGlenn Strauss } 435e6741acdSGlenn Strauss return NULL; 436e6741acdSGlenn Strauss } 437e6741acdSGlenn Strauss 438e6741acdSGlenn Strauss data_unset * 439e6741acdSGlenn Strauss array_match_key_prefix (const array * const a, const buffer * const b) 440e6741acdSGlenn Strauss { 44128f1867cSGlenn Strauss #ifdef __clang_analyzer__ 44228f1867cSGlenn Strauss force_assert(b); 44328f1867cSGlenn Strauss #endif 444e6741acdSGlenn Strauss return array_match_key_prefix_klen(a, CONST_BUF_LEN(b)); 445e6741acdSGlenn Strauss } 446e6741acdSGlenn Strauss 447e6741acdSGlenn Strauss data_unset * 448e6741acdSGlenn Strauss array_match_key_prefix_nc (const array * const a, const buffer * const b) 449e6741acdSGlenn Strauss { 450e6741acdSGlenn Strauss return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b)); 451e6741acdSGlenn Strauss } 452e6741acdSGlenn Strauss 453e6741acdSGlenn Strauss const buffer * 454e6741acdSGlenn Strauss array_match_value_prefix (const array * const a, const buffer * const b) 455e6741acdSGlenn Strauss { 45668ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 457e6741acdSGlenn Strauss 458b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 459601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value; 46068ec5ad6SGlenn Strauss const uint32_t vlen = buffer_string_length(value); 461e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen)) 462e6741acdSGlenn Strauss return value; 463e6741acdSGlenn Strauss } 464e6741acdSGlenn Strauss return NULL; 465e6741acdSGlenn Strauss } 466e6741acdSGlenn Strauss 467e6741acdSGlenn Strauss const buffer * 468e6741acdSGlenn Strauss array_match_value_prefix_nc (const array * const a, const buffer * const b) 469e6741acdSGlenn Strauss { 47068ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 471e6741acdSGlenn Strauss 472b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 473601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value; 47468ec5ad6SGlenn Strauss const uint32_t vlen = buffer_string_length(value); 475e20b5318SGlenn Strauss if (vlen <= blen && buffer_eq_icase_ssn(b->ptr, value->ptr, vlen)) 476e6741acdSGlenn Strauss return value; 477e6741acdSGlenn Strauss } 478e6741acdSGlenn Strauss return NULL; 479e6741acdSGlenn Strauss } 480e6741acdSGlenn Strauss 481e6741acdSGlenn Strauss data_unset * 482e6741acdSGlenn Strauss array_match_key_suffix (const array * const a, const buffer * const b) 483e6741acdSGlenn Strauss { 48468ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 485e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 486e6741acdSGlenn Strauss 487b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 488ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key; 48968ec5ad6SGlenn Strauss const uint32_t klen = buffer_string_length(key); 490e6741acdSGlenn Strauss if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen)) 491e6741acdSGlenn Strauss return a->data[i]; 492e6741acdSGlenn Strauss } 493e6741acdSGlenn Strauss return NULL; 494e6741acdSGlenn Strauss } 495e6741acdSGlenn Strauss 496e6741acdSGlenn Strauss data_unset * 497e6741acdSGlenn Strauss array_match_key_suffix_nc (const array * const a, const buffer * const b) 498e6741acdSGlenn Strauss { 49968ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 500e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 501e6741acdSGlenn Strauss 502b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 503ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key; 50468ec5ad6SGlenn Strauss const uint32_t klen = buffer_string_length(key); 505e20b5318SGlenn Strauss if (klen <= blen && buffer_eq_icase_ssn(end - klen, key->ptr, klen)) 506e6741acdSGlenn Strauss return a->data[i]; 507e6741acdSGlenn Strauss } 508e6741acdSGlenn Strauss return NULL; 509e6741acdSGlenn Strauss } 510e6741acdSGlenn Strauss 511e6741acdSGlenn Strauss const buffer * 512e6741acdSGlenn Strauss array_match_value_suffix (const array * const a, const buffer * const b) 513e6741acdSGlenn Strauss { 51468ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 515e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 516e6741acdSGlenn Strauss 517b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 518601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value; 51968ec5ad6SGlenn Strauss const uint32_t vlen = buffer_string_length(value); 520e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen)) 521e6741acdSGlenn Strauss return value; 522e6741acdSGlenn Strauss } 523e6741acdSGlenn Strauss return NULL; 524e6741acdSGlenn Strauss } 525e6741acdSGlenn Strauss 526e6741acdSGlenn Strauss const buffer * 527e6741acdSGlenn Strauss array_match_value_suffix_nc (const array * const a, const buffer * const b) 528e6741acdSGlenn Strauss { 52968ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 530e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 531e6741acdSGlenn Strauss 532b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 533601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value; 53468ec5ad6SGlenn Strauss const uint32_t vlen = buffer_string_length(value); 535e20b5318SGlenn Strauss if (vlen <= blen && buffer_eq_icase_ssn(end - vlen, value->ptr, vlen)) 536e6741acdSGlenn Strauss return value; 537e6741acdSGlenn Strauss } 538e6741acdSGlenn Strauss return NULL; 539e6741acdSGlenn Strauss } 540e6741acdSGlenn Strauss 541e6741acdSGlenn Strauss data_unset * 542e6741acdSGlenn Strauss array_match_path_or_ext (const array * const a, const buffer * const b) 543e6741acdSGlenn Strauss { 54468ec5ad6SGlenn Strauss const uint32_t blen = buffer_string_length(b); 545e6741acdSGlenn Strauss 546b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 547e6741acdSGlenn Strauss /* check extension in the form "^/path" or ".ext$" */ 548ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key; 54968ec5ad6SGlenn Strauss const uint32_t klen = buffer_string_length(key); 550e6741acdSGlenn Strauss if (klen <= blen 551e6741acdSGlenn Strauss && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen), 552e6741acdSGlenn Strauss key->ptr, klen)) 553e6741acdSGlenn Strauss return a->data[i]; 554e6741acdSGlenn Strauss } 555e6741acdSGlenn Strauss return NULL; 556e6741acdSGlenn Strauss } 557e6741acdSGlenn Strauss 558e6741acdSGlenn Strauss 559e6741acdSGlenn Strauss 560a46bc4f5SGlenn Strauss 561a46bc4f5SGlenn Strauss 562a46bc4f5SGlenn Strauss #include <stdio.h> 563a46bc4f5SGlenn Strauss 5649e75ba00SJan Kneschke void array_print_indent(int depth) { 5659e75ba00SJan Kneschke int i; 5669e75ba00SJan Kneschke for (i = 0; i < depth; i ++) { 567dd0abe5aSJan Kneschke fprintf(stdout, " "); 5689e75ba00SJan Kneschke } 5699e75ba00SJan Kneschke } 5709e75ba00SJan Kneschke 57168ec5ad6SGlenn Strauss uint32_t array_get_max_key_length(const array * const a) { 57268ec5ad6SGlenn Strauss uint32_t maxlen = 0; 573b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) { 574ad9b7e00SGlenn Strauss const buffer * const k = &a->data[i]->key; 57568ec5ad6SGlenn Strauss uint32_t len = buffer_string_length(k); 5766044dbc5SmOo 5776044dbc5SmOo if (len > maxlen) { 5786044dbc5SmOo maxlen = len; 5796044dbc5SmOo } 5806044dbc5SmOo } 5816044dbc5SmOo return maxlen; 5826044dbc5SmOo } 5836044dbc5SmOo 584b2991c68SGlenn Strauss int array_print(const array * const a, int depth) { 585b2991c68SGlenn Strauss uint32_t i; 58668ec5ad6SGlenn Strauss uint32_t maxlen; 5876044dbc5SmOo int oneline = 1; 588bcdc6a3bSJan Kneschke 5896044dbc5SmOo if (a->used > 5) { 5906044dbc5SmOo oneline = 0; 5916044dbc5SmOo } 5926044dbc5SmOo for (i = 0; i < a->used && oneline; i++) { 5936044dbc5SmOo data_unset *du = a->data[i]; 594ad9b7e00SGlenn Strauss if (!buffer_is_empty(&du->key)) { 5956044dbc5SmOo oneline = 0; 5966044dbc5SmOo break; 5976044dbc5SmOo } 5986044dbc5SmOo switch (du->type) { 5996044dbc5SmOo case TYPE_INTEGER: 6006044dbc5SmOo case TYPE_STRING: 6016044dbc5SmOo break; 6026044dbc5SmOo default: 6036044dbc5SmOo oneline = 0; 6046044dbc5SmOo break; 6056044dbc5SmOo } 6066044dbc5SmOo } 6076044dbc5SmOo if (oneline) { 608dd0abe5aSJan Kneschke fprintf(stdout, "("); 609bcdc6a3bSJan Kneschke for (i = 0; i < a->used; i++) { 6106044dbc5SmOo data_unset *du = a->data[i]; 6116044dbc5SmOo if (i != 0) { 612dd0abe5aSJan Kneschke fprintf(stdout, ", "); 6136044dbc5SmOo } 6148c7f1dfbSGlenn Strauss du->fn->print(du, depth + 1); 6156044dbc5SmOo } 616dd0abe5aSJan Kneschke fprintf(stdout, ")"); 6176044dbc5SmOo return 0; 6186044dbc5SmOo } 6196044dbc5SmOo 6206044dbc5SmOo maxlen = array_get_max_key_length(a); 621dd0abe5aSJan Kneschke fprintf(stdout, "(\n"); 6226044dbc5SmOo for (i = 0; i < a->used; i++) { 6236044dbc5SmOo data_unset *du = a->data[i]; 6248b07d57dSJan Kneschke array_print_indent(depth + 1); 625ad9b7e00SGlenn Strauss if (!buffer_is_empty(&du->key)) { 6266044dbc5SmOo int j; 6276044dbc5SmOo 6286044dbc5SmOo if (i && (i % 5) == 0) { 629b2991c68SGlenn Strauss fprintf(stdout, "# %u\n", i); 6306044dbc5SmOo array_print_indent(depth + 1); 6316044dbc5SmOo } 632ad9b7e00SGlenn Strauss fprintf(stdout, "\"%s\"", du->key.ptr); 633ad9b7e00SGlenn Strauss for (j = maxlen - buffer_string_length(&du->key); j > 0; j--) { 634dd0abe5aSJan Kneschke fprintf(stdout, " "); 6356044dbc5SmOo } 636dd0abe5aSJan Kneschke fprintf(stdout, " => "); 6376044dbc5SmOo } 6388c7f1dfbSGlenn Strauss du->fn->print(du, depth + 1); 639dd0abe5aSJan Kneschke fprintf(stdout, ",\n"); 6406044dbc5SmOo } 6416044dbc5SmOo if (!(i && (i - 1 % 5) == 0)) { 6426044dbc5SmOo array_print_indent(depth + 1); 643b2991c68SGlenn Strauss fprintf(stdout, "# %u\n", i); 644bcdc6a3bSJan Kneschke } 6458b07d57dSJan Kneschke array_print_indent(depth); 646dd0abe5aSJan Kneschke fprintf(stdout, ")"); 647bcdc6a3bSJan Kneschke 648bcdc6a3bSJan Kneschke return 0; 649bcdc6a3bSJan Kneschke } 650