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 10bcdc6a3bSJan Kneschke #include <errno.h> 11bcdc6a3bSJan Kneschke #include <assert.h> 12bcdc6a3bSJan Kneschke 13224bf545SStefan Bühler #define ARRAY_NOT_FOUND ((size_t)(-1)) 14224bf545SStefan Bühler 15bcdc6a3bSJan Kneschke array *array_init(void) { 16bcdc6a3bSJan Kneschke array *a; 17bcdc6a3bSJan Kneschke 18bcdc6a3bSJan Kneschke a = calloc(1, sizeof(*a)); 1907dd0bd0SStefan Bühler force_assert(a); 20bcdc6a3bSJan Kneschke 21bcdc6a3bSJan Kneschke return a; 22bcdc6a3bSJan Kneschke } 23bcdc6a3bSJan Kneschke 246e78c2c8SJan Kneschke array *array_init_array(array *src) { 256e78c2c8SJan Kneschke size_t i; 266e78c2c8SJan Kneschke array *a = array_init(); 276e78c2c8SJan Kneschke 286f208cfdSStefan Bühler if (0 == src->size) return a; 296f208cfdSStefan Bühler 306e78c2c8SJan Kneschke a->used = src->used; 316e78c2c8SJan Kneschke a->size = src->size; 326e78c2c8SJan Kneschke a->unique_ndx = src->unique_ndx; 336e78c2c8SJan Kneschke 346e78c2c8SJan Kneschke a->data = malloc(sizeof(*src->data) * src->size); 35566cf8deSStefan Bühler force_assert(NULL != a->data); 366e78c2c8SJan Kneschke for (i = 0; i < src->size; i++) { 376e78c2c8SJan Kneschke if (src->data[i]) a->data[i] = src->data[i]->copy(src->data[i]); 386e78c2c8SJan Kneschke else a->data[i] = NULL; 396e78c2c8SJan Kneschke } 406e78c2c8SJan Kneschke 416e78c2c8SJan Kneschke a->sorted = malloc(sizeof(*src->sorted) * src->size); 42566cf8deSStefan Bühler force_assert(NULL != a->sorted); 436e78c2c8SJan Kneschke memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size); 446e78c2c8SJan Kneschke return a; 456e78c2c8SJan Kneschke } 466e78c2c8SJan Kneschke 47bcdc6a3bSJan Kneschke void array_free(array *a) { 48bcdc6a3bSJan Kneschke size_t i; 49bcdc6a3bSJan Kneschke if (!a) return; 50bcdc6a3bSJan Kneschke 51bcdc6a3bSJan Kneschke for (i = 0; i < a->size; i++) { 52bcdc6a3bSJan Kneschke if (a->data[i]) a->data[i]->free(a->data[i]); 53bcdc6a3bSJan Kneschke } 54bcdc6a3bSJan Kneschke 55bcdc6a3bSJan Kneschke if (a->data) free(a->data); 56bcdc6a3bSJan Kneschke if (a->sorted) free(a->sorted); 57bcdc6a3bSJan Kneschke 58bcdc6a3bSJan Kneschke free(a); 59bcdc6a3bSJan Kneschke } 60bcdc6a3bSJan Kneschke 61bcdc6a3bSJan Kneschke void array_reset(array *a) { 62bcdc6a3bSJan Kneschke size_t i; 63bcdc6a3bSJan Kneschke if (!a) return; 64bcdc6a3bSJan Kneschke 65bcdc6a3bSJan Kneschke for (i = 0; i < a->used; i++) { 66bcdc6a3bSJan Kneschke a->data[i]->reset(a->data[i]); 67bcdc6a3bSJan Kneschke } 68bcdc6a3bSJan Kneschke 69bcdc6a3bSJan Kneschke a->used = 0; 708d8ae9cbSStefan Bühler a->unique_ndx = 0; 71bcdc6a3bSJan Kneschke } 72bcdc6a3bSJan Kneschke 738073d5feSJan Kneschke data_unset *array_pop(array *a) { 748073d5feSJan Kneschke data_unset *du; 758073d5feSJan Kneschke 7607dd0bd0SStefan Bühler force_assert(a->used != 0); 778073d5feSJan Kneschke 788073d5feSJan Kneschke a->used --; 798073d5feSJan Kneschke du = a->data[a->used]; 808d8ae9cbSStefan Bühler force_assert(a->sorted[a->used] == a->used); /* only works on "simple" lists */ 818073d5feSJan Kneschke a->data[a->used] = NULL; 828073d5feSJan Kneschke 838073d5feSJan Kneschke return du; 848073d5feSJan Kneschke } 858073d5feSJan Kneschke 86224bf545SStefan Bühler /* returns index of element or ARRAY_NOT_FOUND 87224bf545SStefan Bühler * if rndx != NULL it stores the position in a->sorted[] where the key needs 88224bf545SStefan Bühler * to be inserted 89224bf545SStefan Bühler */ 902496c1afSGlenn Strauss static size_t array_get_index(const array *a, const char *key, size_t keylen, size_t *rndx) { 91224bf545SStefan Bühler /* invariant: [lower-1] < key < [upper] 92224bf545SStefan Bühler * "virtual elements": [-1] = -INFTY, [a->used] = +INFTY 93224bf545SStefan Bühler * also an invariant: 0 <= lower <= upper <= a->used 94224bf545SStefan Bühler */ 95224bf545SStefan Bühler size_t lower = 0, upper = a->used; 96224bf545SStefan Bühler force_assert(upper <= SSIZE_MAX); /* (lower + upper) can't overflow */ 97bcdc6a3bSJan Kneschke 98224bf545SStefan Bühler while (lower != upper) { 99224bf545SStefan Bühler size_t probe = (lower + upper) / 2; 100224bf545SStefan Bühler int cmp = buffer_caseless_compare(key, keylen, CONST_BUF_LEN(a->data[a->sorted[probe]]->key)); 101224bf545SStefan Bühler assert(lower < upper); /* from loop invariant (lower <= upper) + (lower != upper) */ 102224bf545SStefan Bühler assert((lower <= probe) && (probe < upper)); /* follows from lower < upper */ 103bcdc6a3bSJan Kneschke 104bcdc6a3bSJan Kneschke if (cmp == 0) { 105bcdc6a3bSJan Kneschke /* found */ 106224bf545SStefan Bühler if (rndx) *rndx = probe; 107224bf545SStefan Bühler return a->sorted[probe]; 108bcdc6a3bSJan Kneschke } else if (cmp < 0) { 109224bf545SStefan Bühler /* key < [probe] */ 110224bf545SStefan Bühler upper = probe; /* still: lower <= upper */ 111bcdc6a3bSJan Kneschke } else { 112224bf545SStefan Bühler /* key > [probe] */ 113224bf545SStefan Bühler lower = probe + 1; /* still: lower <= upper */ 114bcdc6a3bSJan Kneschke } 115bcdc6a3bSJan Kneschke } 116bcdc6a3bSJan Kneschke 117224bf545SStefan Bühler /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 118224bf545SStefan Bühler if (rndx) *rndx = lower; 119224bf545SStefan Bühler return ARRAY_NOT_FOUND; 120bcdc6a3bSJan Kneschke } 121bcdc6a3bSJan Kneschke 1222496c1afSGlenn Strauss data_unset *array_get_element_klen(const array *a, const char *key, size_t klen) { 123224bf545SStefan Bühler size_t ndx; 124224bf545SStefan Bühler force_assert(NULL != key); 125bcdc6a3bSJan Kneschke 12686bb8be2SGlenn Strauss if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, NULL))) { 127224bf545SStefan Bühler /* found, return it */ 128bcdc6a3bSJan Kneschke return a->data[ndx]; 129bcdc6a3bSJan Kneschke } 130bcdc6a3bSJan Kneschke 131bcdc6a3bSJan Kneschke return NULL; 132bcdc6a3bSJan Kneschke } 133bcdc6a3bSJan Kneschke 13486bb8be2SGlenn Strauss data_unset *array_extract_element_klen(array *a, const char *key, size_t klen) { 13568e4a416SStefan Bühler size_t ndx, pos; 13668e4a416SStefan Bühler force_assert(NULL != key); 13768e4a416SStefan Bühler 13886bb8be2SGlenn Strauss if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, &pos))) { 13968e4a416SStefan Bühler /* found */ 14068e4a416SStefan Bühler const size_t last_ndx = a->used - 1; 14168e4a416SStefan Bühler data_unset *entry = a->data[ndx]; 14268e4a416SStefan Bühler 14368e4a416SStefan Bühler /* now we need to swap it with the last element (if it isn't already the last element) */ 14468e4a416SStefan Bühler if (ndx != last_ndx) { 14568e4a416SStefan Bühler /* to swap we also need to modify the index in a->sorted - find pos of last_elem there */ 14668e4a416SStefan Bühler size_t last_elem_pos; 14768e4a416SStefan Bühler /* last element must be present at the expected position */ 14868e4a416SStefan Bühler force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos)); 14968e4a416SStefan Bühler 15068e4a416SStefan Bühler /* move entry from last_ndx to ndx */ 15168e4a416SStefan Bühler a->data[ndx] = a->data[last_ndx]; 15268e4a416SStefan Bühler a->data[last_ndx] = NULL; 15368e4a416SStefan Bühler 15468e4a416SStefan Bühler /* fix index entry for moved entry */ 15568e4a416SStefan Bühler a->sorted[last_elem_pos] = ndx; 15668e4a416SStefan Bühler } else { 15768e4a416SStefan Bühler a->data[ndx] = NULL; 15868e4a416SStefan Bühler } 15968e4a416SStefan Bühler 16068e4a416SStefan Bühler /* remove entry in a->sorted: move everything after pos one step to the left */ 16168e4a416SStefan Bühler if (pos != last_ndx) { 16268e4a416SStefan Bühler memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted)); 16368e4a416SStefan Bühler } 16468e4a416SStefan Bühler a->sorted[last_ndx] = ARRAY_NOT_FOUND; 16568e4a416SStefan Bühler --a->used; 16668e4a416SStefan Bühler 16768e4a416SStefan Bühler return entry; 16868e4a416SStefan Bühler } 16968e4a416SStefan Bühler 17068e4a416SStefan Bühler return NULL; 17168e4a416SStefan Bühler } 17268e4a416SStefan Bühler 173a7c27c9fSGlenn Strauss static data_unset *array_get_unused_element(array *a, data_type_t t) { 174bcdc6a3bSJan Kneschke data_unset *ds = NULL; 17512f375f3SStefan Bühler unsigned int i; 176bcdc6a3bSJan Kneschke 17712f375f3SStefan Bühler for (i = a->used; i < a->size; i++) { 17812f375f3SStefan Bühler if (a->data[i] && a->data[i]->type == t) { 17912f375f3SStefan Bühler ds = a->data[i]; 180bcdc6a3bSJan Kneschke 18112f375f3SStefan Bühler /* make empty slot at a->used for next insert */ 18212f375f3SStefan Bühler a->data[i] = a->data[a->used]; 183bcdc6a3bSJan Kneschke a->data[a->used] = NULL; 184bcdc6a3bSJan Kneschke 185bcdc6a3bSJan Kneschke return ds; 186bcdc6a3bSJan Kneschke } 18712f375f3SStefan Bühler } 18812f375f3SStefan Bühler 18912f375f3SStefan Bühler return NULL; 19012f375f3SStefan Bühler } 191bcdc6a3bSJan Kneschke 1924f4d40f3SStefan Bühler void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 193a7c27c9fSGlenn Strauss data_string *ds; 1944f4d40f3SStefan Bühler 195a7c27c9fSGlenn Strauss if (NULL != (ds = (data_string *)array_get_element_klen(hdrs, key, key_len))) { 196a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 1974f4d40f3SStefan Bühler return; 1984f4d40f3SStefan Bühler } 1994f4d40f3SStefan Bühler 200a7c27c9fSGlenn Strauss array_insert_key_value(hdrs, key, key_len, value, val_len); 2014f4d40f3SStefan Bühler } 2024f4d40f3SStefan Bühler 203a7c27c9fSGlenn Strauss void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 204a7c27c9fSGlenn Strauss data_string *ds; 205a7c27c9fSGlenn Strauss 206a7c27c9fSGlenn Strauss if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 207a7c27c9fSGlenn Strauss ds = data_string_init(); 208a7c27c9fSGlenn Strauss } 209a7c27c9fSGlenn Strauss 210a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->key, key, key_len); 211a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 212a7c27c9fSGlenn Strauss array_insert_unique(hdrs, (data_unset *)ds); 213a7c27c9fSGlenn Strauss } 214a7c27c9fSGlenn Strauss 215a7c27c9fSGlenn Strauss void array_insert_value(array *hdrs, const char *value, size_t val_len) { 216a7c27c9fSGlenn Strauss data_string *ds; 217a7c27c9fSGlenn Strauss 218a7c27c9fSGlenn Strauss if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 219a7c27c9fSGlenn Strauss ds = data_string_init(); 220a7c27c9fSGlenn Strauss } 221a7c27c9fSGlenn Strauss 222a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 223a7c27c9fSGlenn Strauss array_insert_unique(hdrs, (data_unset *)ds); 2244f4d40f3SStefan Bühler } 2254f4d40f3SStefan Bühler 226*002a4c52SGlenn Strauss int * array_get_int_ptr(array *a, const char *k, size_t klen) { 227*002a4c52SGlenn Strauss data_integer *di = (data_integer *)array_get_element_klen(a, k, klen); 228*002a4c52SGlenn Strauss 229*002a4c52SGlenn Strauss if (NULL == di) { 230*002a4c52SGlenn Strauss di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER); 231*002a4c52SGlenn Strauss if (NULL == di) di = data_integer_init(); 232*002a4c52SGlenn Strauss buffer_copy_string_len(di->key, k, klen); 233*002a4c52SGlenn Strauss array_insert_unique(a, (data_unset *)di); 234*002a4c52SGlenn Strauss } 235*002a4c52SGlenn Strauss 236*002a4c52SGlenn Strauss return &di->value; 237*002a4c52SGlenn Strauss } 238*002a4c52SGlenn Strauss 2398d8ae9cbSStefan Bühler /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */ 240be121a63SStefan Bühler static data_unset **array_find_or_insert(array *a, data_unset *entry) { 241224bf545SStefan Bühler size_t ndx, pos, j; 242bcdc6a3bSJan Kneschke 243bcdc6a3bSJan Kneschke /* generate unique index if neccesary */ 244be121a63SStefan Bühler if (buffer_is_empty(entry->key) || entry->is_index_key) { 245be121a63SStefan Bühler buffer_copy_int(entry->key, a->unique_ndx++); 246be121a63SStefan Bühler entry->is_index_key = 1; 2478d8ae9cbSStefan Bühler force_assert(0 != a->unique_ndx); /* must not wrap or we'll get problems */ 248bcdc6a3bSJan Kneschke } 249bcdc6a3bSJan Kneschke 250be121a63SStefan Bühler /* try to find the entry */ 251224bf545SStefan Bühler if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, CONST_BUF_LEN(entry->key), &pos))) { 2528d8ae9cbSStefan Bühler /* found collision, return it */ 2538d8ae9cbSStefan Bühler return &a->data[ndx]; 254bcdc6a3bSJan Kneschke } 255bcdc6a3bSJan Kneschke 256bcdc6a3bSJan Kneschke /* insert */ 257bcdc6a3bSJan Kneschke 258224bf545SStefan Bühler /* there couldn't possibly be enough memory to store so many entries */ 259224bf545SStefan Bühler force_assert(a->used + 1 <= SSIZE_MAX); 260bcdc6a3bSJan Kneschke 261bcdc6a3bSJan Kneschke if (a->size == 0) { 262bcdc6a3bSJan Kneschke a->size = 16; 263bcdc6a3bSJan Kneschke a->data = malloc(sizeof(*a->data) * a->size); 264bcdc6a3bSJan Kneschke a->sorted = malloc(sizeof(*a->sorted) * a->size); 26507dd0bd0SStefan Bühler force_assert(a->data); 26607dd0bd0SStefan Bühler force_assert(a->sorted); 267bcdc6a3bSJan Kneschke for (j = a->used; j < a->size; j++) a->data[j] = NULL; 268bcdc6a3bSJan Kneschke } else if (a->size == a->used) { 269bcdc6a3bSJan Kneschke a->size += 16; 270bcdc6a3bSJan Kneschke a->data = realloc(a->data, sizeof(*a->data) * a->size); 271bcdc6a3bSJan Kneschke a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size); 27207dd0bd0SStefan Bühler force_assert(a->data); 27307dd0bd0SStefan Bühler force_assert(a->sorted); 274bcdc6a3bSJan Kneschke for (j = a->used; j < a->size; j++) a->data[j] = NULL; 275bcdc6a3bSJan Kneschke } 276bcdc6a3bSJan Kneschke 277224bf545SStefan Bühler ndx = a->used; 278bcdc6a3bSJan Kneschke 27912f375f3SStefan Bühler /* make sure there is nothing here */ 28012f375f3SStefan Bühler if (a->data[ndx]) a->data[ndx]->free(a->data[ndx]); 28112f375f3SStefan Bühler 282be121a63SStefan Bühler a->data[a->used++] = entry; 283bcdc6a3bSJan Kneschke 2848d8ae9cbSStefan Bühler /* move everything one step to the right */ 285bcdc6a3bSJan Kneschke if (pos != ndx) { 286bcdc6a3bSJan Kneschke memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted)); 287bcdc6a3bSJan Kneschke } 288bcdc6a3bSJan Kneschke 289bcdc6a3bSJan Kneschke /* insert */ 290bcdc6a3bSJan Kneschke a->sorted[pos] = ndx; 291bcdc6a3bSJan Kneschke 2928d8ae9cbSStefan Bühler return NULL; 2938d8ae9cbSStefan Bühler } 2948d8ae9cbSStefan Bühler 2958d8ae9cbSStefan Bühler /* replace or insert data (free existing entry) */ 2968d8ae9cbSStefan Bühler void array_replace(array *a, data_unset *entry) { 2978d8ae9cbSStefan Bühler data_unset **old; 2988d8ae9cbSStefan Bühler 2998d8ae9cbSStefan Bühler force_assert(NULL != entry); 3008d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) { 3018d8ae9cbSStefan Bühler force_assert(*old != entry); 3028d8ae9cbSStefan Bühler (*old)->free(*old); 3038d8ae9cbSStefan Bühler *old = entry; 3048d8ae9cbSStefan Bühler } 3058d8ae9cbSStefan Bühler } 3068d8ae9cbSStefan Bühler 3078d8ae9cbSStefan Bühler void array_insert_unique(array *a, data_unset *entry) { 3088d8ae9cbSStefan Bühler data_unset **old; 3098d8ae9cbSStefan Bühler 3108d8ae9cbSStefan Bühler force_assert(NULL != entry); 3118d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) { 3128d8ae9cbSStefan Bühler force_assert((*old)->type == entry->type); 3138d8ae9cbSStefan Bühler entry->insert_dup(*old, entry); 3148d8ae9cbSStefan Bühler } 315bcdc6a3bSJan Kneschke } 316bcdc6a3bSJan Kneschke 317bd77abe0SGlenn Strauss int array_is_vlist(array *a) { 318bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 319bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 320bd77abe0SGlenn Strauss if (!du->is_index_key || du->type != TYPE_STRING) return 0; 321bd77abe0SGlenn Strauss } 322bd77abe0SGlenn Strauss return 1; 323bd77abe0SGlenn Strauss } 324bd77abe0SGlenn Strauss 325bd77abe0SGlenn Strauss int array_is_kvany(array *a) { 326bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 327bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 328bd77abe0SGlenn Strauss if (du->is_index_key) return 0; 329bd77abe0SGlenn Strauss } 330bd77abe0SGlenn Strauss return 1; 331bd77abe0SGlenn Strauss } 332bd77abe0SGlenn Strauss 333bd77abe0SGlenn Strauss int array_is_kvarray(array *a) { 334bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 335bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 336bd77abe0SGlenn Strauss if (du->is_index_key || du->type != TYPE_ARRAY) return 0; 337bd77abe0SGlenn Strauss } 338bd77abe0SGlenn Strauss return 1; 339bd77abe0SGlenn Strauss } 340bd77abe0SGlenn Strauss 341bd77abe0SGlenn Strauss int array_is_kvstring(array *a) { 342bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 343bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 344bd77abe0SGlenn Strauss if (du->is_index_key || du->type != TYPE_STRING) return 0; 345bd77abe0SGlenn Strauss } 346bd77abe0SGlenn Strauss return 1; 347bd77abe0SGlenn Strauss } 348bd77abe0SGlenn Strauss 349e6741acdSGlenn Strauss /* array_match_*() routines follow very similar pattern, but operate on slightly 350e6741acdSGlenn Strauss * different data: array key/value, prefix/suffix match, case-insensitive or not 351e6741acdSGlenn Strauss * While these could be combined into fewer routines with flags to modify the 352e6741acdSGlenn Strauss * behavior, the interface distinctions are useful to add clarity to the code, 353e6741acdSGlenn Strauss * and the specialized routines run slightly faster */ 354e6741acdSGlenn Strauss 355e6741acdSGlenn Strauss data_unset * 356e6741acdSGlenn Strauss array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen) 357e6741acdSGlenn Strauss { 358e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 359e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 360e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 361e6741acdSGlenn Strauss if (klen <= slen && 0 == memcmp(s, key->ptr, klen)) 362e6741acdSGlenn Strauss return a->data[i]; 363e6741acdSGlenn Strauss } 364e6741acdSGlenn Strauss return NULL; 365e6741acdSGlenn Strauss } 366e6741acdSGlenn Strauss 367e6741acdSGlenn Strauss data_unset * 368e6741acdSGlenn Strauss array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen) 369e6741acdSGlenn Strauss { 370e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 371e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 372e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 373e6741acdSGlenn Strauss if (klen <= slen && 0 == strncasecmp(s, key->ptr, klen)) 374e6741acdSGlenn Strauss return a->data[i]; 375e6741acdSGlenn Strauss } 376e6741acdSGlenn Strauss return NULL; 377e6741acdSGlenn Strauss } 378e6741acdSGlenn Strauss 379e6741acdSGlenn Strauss data_unset * 380e6741acdSGlenn Strauss array_match_key_prefix (const array * const a, const buffer * const b) 381e6741acdSGlenn Strauss { 382e6741acdSGlenn Strauss return array_match_key_prefix_klen(a, CONST_BUF_LEN(b)); 383e6741acdSGlenn Strauss } 384e6741acdSGlenn Strauss 385e6741acdSGlenn Strauss data_unset * 386e6741acdSGlenn Strauss array_match_key_prefix_nc (const array * const a, const buffer * const b) 387e6741acdSGlenn Strauss { 388e6741acdSGlenn Strauss return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b)); 389e6741acdSGlenn Strauss } 390e6741acdSGlenn Strauss 391e6741acdSGlenn Strauss const buffer * 392e6741acdSGlenn Strauss array_match_value_prefix (const array * const a, const buffer * const b) 393e6741acdSGlenn Strauss { 394e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 395e6741acdSGlenn Strauss 396e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 397e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 398e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 399e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen)) 400e6741acdSGlenn Strauss return value; 401e6741acdSGlenn Strauss } 402e6741acdSGlenn Strauss return NULL; 403e6741acdSGlenn Strauss } 404e6741acdSGlenn Strauss 405e6741acdSGlenn Strauss const buffer * 406e6741acdSGlenn Strauss array_match_value_prefix_nc (const array * const a, const buffer * const b) 407e6741acdSGlenn Strauss { 408e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 409e6741acdSGlenn Strauss 410e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 411e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 412e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 413e6741acdSGlenn Strauss if (vlen <= blen && 0 == strncasecmp(b->ptr, value->ptr, vlen)) 414e6741acdSGlenn Strauss return value; 415e6741acdSGlenn Strauss } 416e6741acdSGlenn Strauss return NULL; 417e6741acdSGlenn Strauss } 418e6741acdSGlenn Strauss 419e6741acdSGlenn Strauss data_unset * 420e6741acdSGlenn Strauss array_match_key_suffix (const array * const a, const buffer * const b) 421e6741acdSGlenn Strauss { 422e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 423e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 424e6741acdSGlenn Strauss 425e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 426e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 427e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 428e6741acdSGlenn Strauss if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen)) 429e6741acdSGlenn Strauss return a->data[i]; 430e6741acdSGlenn Strauss } 431e6741acdSGlenn Strauss return NULL; 432e6741acdSGlenn Strauss } 433e6741acdSGlenn Strauss 434e6741acdSGlenn Strauss data_unset * 435e6741acdSGlenn Strauss array_match_key_suffix_nc (const array * const a, const buffer * const b) 436e6741acdSGlenn Strauss { 437e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 438e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 439e6741acdSGlenn Strauss 440e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 441e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 442e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 443e6741acdSGlenn Strauss if (klen <= blen && 0 == strncasecmp(end - klen, key->ptr, klen)) 444e6741acdSGlenn Strauss return a->data[i]; 445e6741acdSGlenn Strauss } 446e6741acdSGlenn Strauss return NULL; 447e6741acdSGlenn Strauss } 448e6741acdSGlenn Strauss 449e6741acdSGlenn Strauss const buffer * 450e6741acdSGlenn Strauss array_match_value_suffix (const array * const a, const buffer * const b) 451e6741acdSGlenn Strauss { 452e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 453e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 454e6741acdSGlenn Strauss 455e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 456e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 457e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 458e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen)) 459e6741acdSGlenn Strauss return value; 460e6741acdSGlenn Strauss } 461e6741acdSGlenn Strauss return NULL; 462e6741acdSGlenn Strauss } 463e6741acdSGlenn Strauss 464e6741acdSGlenn Strauss const buffer * 465e6741acdSGlenn Strauss array_match_value_suffix_nc (const array * const a, const buffer * const b) 466e6741acdSGlenn Strauss { 467e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 468e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 469e6741acdSGlenn Strauss 470e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 471e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 472e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 473e6741acdSGlenn Strauss if (vlen <= blen && 0 == strncasecmp(end - vlen, value->ptr, vlen)) 474e6741acdSGlenn Strauss return value; 475e6741acdSGlenn Strauss } 476e6741acdSGlenn Strauss return NULL; 477e6741acdSGlenn Strauss } 478e6741acdSGlenn Strauss 479e6741acdSGlenn Strauss data_unset * 480e6741acdSGlenn Strauss array_match_path_or_ext (const array * const a, const buffer * const b) 481e6741acdSGlenn Strauss { 482e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 483e6741acdSGlenn Strauss 484e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 485e6741acdSGlenn Strauss /* check extension in the form "^/path" or ".ext$" */ 486e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 487e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 488e6741acdSGlenn Strauss if (klen <= blen 489e6741acdSGlenn Strauss && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen), 490e6741acdSGlenn Strauss key->ptr, klen)) 491e6741acdSGlenn Strauss return a->data[i]; 492e6741acdSGlenn Strauss } 493e6741acdSGlenn Strauss return NULL; 494e6741acdSGlenn Strauss } 495e6741acdSGlenn Strauss 496e6741acdSGlenn Strauss 497e6741acdSGlenn Strauss 498a46bc4f5SGlenn Strauss 499a46bc4f5SGlenn Strauss 500a46bc4f5SGlenn Strauss #include <stdio.h> 501a46bc4f5SGlenn Strauss 5029e75ba00SJan Kneschke void array_print_indent(int depth) { 5039e75ba00SJan Kneschke int i; 5049e75ba00SJan Kneschke for (i = 0; i < depth; i ++) { 505dd0abe5aSJan Kneschke fprintf(stdout, " "); 5069e75ba00SJan Kneschke } 5079e75ba00SJan Kneschke } 5089e75ba00SJan Kneschke 5096044dbc5SmOo size_t array_get_max_key_length(array *a) { 5106044dbc5SmOo size_t maxlen, i; 5116044dbc5SmOo 5126044dbc5SmOo maxlen = 0; 5136044dbc5SmOo for (i = 0; i < a->used; i ++) { 5146044dbc5SmOo data_unset *du = a->data[i]; 51586bb8be2SGlenn Strauss size_t len = buffer_string_length(du->key); 5166044dbc5SmOo 5176044dbc5SmOo if (len > maxlen) { 5186044dbc5SmOo maxlen = len; 5196044dbc5SmOo } 5206044dbc5SmOo } 5216044dbc5SmOo return maxlen; 5226044dbc5SmOo } 5236044dbc5SmOo 5249e75ba00SJan Kneschke int array_print(array *a, int depth) { 525bcdc6a3bSJan Kneschke size_t i; 5266044dbc5SmOo size_t maxlen; 5276044dbc5SmOo int oneline = 1; 528bcdc6a3bSJan Kneschke 5296044dbc5SmOo if (a->used > 5) { 5306044dbc5SmOo oneline = 0; 5316044dbc5SmOo } 5326044dbc5SmOo for (i = 0; i < a->used && oneline; i++) { 5336044dbc5SmOo data_unset *du = a->data[i]; 534f387d898SmOo if (!du->is_index_key) { 5356044dbc5SmOo oneline = 0; 5366044dbc5SmOo break; 5376044dbc5SmOo } 5386044dbc5SmOo switch (du->type) { 5396044dbc5SmOo case TYPE_INTEGER: 5406044dbc5SmOo case TYPE_STRING: 5416044dbc5SmOo break; 5426044dbc5SmOo default: 5436044dbc5SmOo oneline = 0; 5446044dbc5SmOo break; 5456044dbc5SmOo } 5466044dbc5SmOo } 5476044dbc5SmOo if (oneline) { 548dd0abe5aSJan Kneschke fprintf(stdout, "("); 549bcdc6a3bSJan Kneschke for (i = 0; i < a->used; i++) { 5506044dbc5SmOo data_unset *du = a->data[i]; 5516044dbc5SmOo if (i != 0) { 552dd0abe5aSJan Kneschke fprintf(stdout, ", "); 5536044dbc5SmOo } 5546044dbc5SmOo du->print(du, depth + 1); 5556044dbc5SmOo } 556dd0abe5aSJan Kneschke fprintf(stdout, ")"); 5576044dbc5SmOo return 0; 5586044dbc5SmOo } 5596044dbc5SmOo 5606044dbc5SmOo maxlen = array_get_max_key_length(a); 561dd0abe5aSJan Kneschke fprintf(stdout, "(\n"); 5626044dbc5SmOo for (i = 0; i < a->used; i++) { 5636044dbc5SmOo data_unset *du = a->data[i]; 5648b07d57dSJan Kneschke array_print_indent(depth + 1); 565f387d898SmOo if (!du->is_index_key) { 5666044dbc5SmOo int j; 5676044dbc5SmOo 5686044dbc5SmOo if (i && (i % 5) == 0) { 569acad2c90SGlenn Strauss fprintf(stdout, "# %zu\n", i); 5706044dbc5SmOo array_print_indent(depth + 1); 5716044dbc5SmOo } 572dd0abe5aSJan Kneschke fprintf(stdout, "\"%s\"", du->key->ptr); 57386bb8be2SGlenn Strauss for (j = maxlen - buffer_string_length(du->key); j > 0; j--) { 574dd0abe5aSJan Kneschke fprintf(stdout, " "); 5756044dbc5SmOo } 576dd0abe5aSJan Kneschke fprintf(stdout, " => "); 5776044dbc5SmOo } 5786044dbc5SmOo du->print(du, depth + 1); 579dd0abe5aSJan Kneschke fprintf(stdout, ",\n"); 5806044dbc5SmOo } 5816044dbc5SmOo if (!(i && (i - 1 % 5) == 0)) { 5826044dbc5SmOo array_print_indent(depth + 1); 583acad2c90SGlenn Strauss fprintf(stdout, "# %zu\n", i); 584bcdc6a3bSJan Kneschke } 5858b07d57dSJan Kneschke array_print_indent(depth); 586dd0abe5aSJan Kneschke fprintf(stdout, ")"); 587bcdc6a3bSJan Kneschke 588bcdc6a3bSJan Kneschke return 0; 589bcdc6a3bSJan Kneschke } 590