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++) { 378c7f1dfbSGlenn Strauss if (src->data[i]) a->data[i] = src->data[i]->fn->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++) { 528c7f1dfbSGlenn Strauss if (a->data[i]) a->data[i]->fn->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++) { 668c7f1dfbSGlenn Strauss a->data[i]->fn->reset(a->data[i]); 67bcdc6a3bSJan Kneschke } 68bcdc6a3bSJan Kneschke 69bcdc6a3bSJan Kneschke a->used = 0; 708d8ae9cbSStefan Bühler a->unique_ndx = 0; 71bcdc6a3bSJan Kneschke } 72bcdc6a3bSJan Kneschke 73062089ffSGlenn Strauss void array_reset_data_strings(array *a) { 74062089ffSGlenn Strauss if (!a) return; 75062089ffSGlenn Strauss 76062089ffSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 77062089ffSGlenn Strauss data_string * const ds = (data_string *)a->data[i]; 78062089ffSGlenn Strauss /*force_assert(ds->type == TYPE_STRING);*/ 79062089ffSGlenn Strauss buffer_reset(ds->key); 80062089ffSGlenn Strauss buffer_reset(ds->value); 81062089ffSGlenn Strauss } 82062089ffSGlenn Strauss 83062089ffSGlenn Strauss a->used = 0; 84062089ffSGlenn Strauss a->unique_ndx = 0; 85062089ffSGlenn Strauss } 86062089ffSGlenn Strauss 878073d5feSJan Kneschke data_unset *array_pop(array *a) { 888073d5feSJan Kneschke data_unset *du; 898073d5feSJan Kneschke 9007dd0bd0SStefan Bühler force_assert(a->used != 0); 918073d5feSJan Kneschke 928073d5feSJan Kneschke a->used --; 938073d5feSJan Kneschke du = a->data[a->used]; 948d8ae9cbSStefan Bühler force_assert(a->sorted[a->used] == a->used); /* only works on "simple" lists */ 958073d5feSJan Kneschke a->data[a->used] = NULL; 968073d5feSJan Kneschke 978073d5feSJan Kneschke return du; 988073d5feSJan Kneschke } 998073d5feSJan Kneschke 100758174ecSGlenn Strauss static int array_keycmp(const char *a, size_t alen, const char *b, size_t blen) { 101758174ecSGlenn Strauss return alen < blen ? -1 : alen > blen ? 1 : buffer_caseless_compare(a, alen, b, blen); 102758174ecSGlenn Strauss } 103758174ecSGlenn Strauss 104224bf545SStefan Bühler /* returns index of element or ARRAY_NOT_FOUND 105224bf545SStefan Bühler * if rndx != NULL it stores the position in a->sorted[] where the key needs 106224bf545SStefan Bühler * to be inserted 107224bf545SStefan Bühler */ 1082496c1afSGlenn Strauss static size_t array_get_index(const array *a, const char *key, size_t keylen, size_t *rndx) { 109224bf545SStefan Bühler /* invariant: [lower-1] < key < [upper] 110224bf545SStefan Bühler * "virtual elements": [-1] = -INFTY, [a->used] = +INFTY 111224bf545SStefan Bühler * also an invariant: 0 <= lower <= upper <= a->used 112224bf545SStefan Bühler */ 113224bf545SStefan Bühler size_t lower = 0, upper = a->used; 114224bf545SStefan Bühler force_assert(upper <= SSIZE_MAX); /* (lower + upper) can't overflow */ 115bcdc6a3bSJan Kneschke 116224bf545SStefan Bühler while (lower != upper) { 117224bf545SStefan Bühler size_t probe = (lower + upper) / 2; 118758174ecSGlenn Strauss const buffer *b = a->data[a->sorted[probe]]->key; 119758174ecSGlenn Strauss int cmp = array_keycmp(key, keylen, CONST_BUF_LEN(b)); 120bcdc6a3bSJan Kneschke 121bcdc6a3bSJan Kneschke if (cmp == 0) { 122bcdc6a3bSJan Kneschke /* found */ 123224bf545SStefan Bühler if (rndx) *rndx = probe; 124224bf545SStefan Bühler return a->sorted[probe]; 125bcdc6a3bSJan Kneschke } else if (cmp < 0) { 126224bf545SStefan Bühler /* key < [probe] */ 127224bf545SStefan Bühler upper = probe; /* still: lower <= upper */ 128bcdc6a3bSJan Kneschke } else { 129224bf545SStefan Bühler /* key > [probe] */ 130224bf545SStefan Bühler lower = probe + 1; /* still: lower <= upper */ 131bcdc6a3bSJan Kneschke } 132bcdc6a3bSJan Kneschke } 133bcdc6a3bSJan Kneschke 134224bf545SStefan Bühler /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ 135224bf545SStefan Bühler if (rndx) *rndx = lower; 136224bf545SStefan Bühler return ARRAY_NOT_FOUND; 137bcdc6a3bSJan Kneschke } 138bcdc6a3bSJan Kneschke 1392496c1afSGlenn Strauss data_unset *array_get_element_klen(const array *a, const char *key, size_t klen) { 140224bf545SStefan Bühler size_t ndx; 141224bf545SStefan Bühler force_assert(NULL != key); 142bcdc6a3bSJan Kneschke 14386bb8be2SGlenn Strauss if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, NULL))) { 144224bf545SStefan Bühler /* found, return it */ 145bcdc6a3bSJan Kneschke return a->data[ndx]; 146bcdc6a3bSJan Kneschke } 147bcdc6a3bSJan Kneschke 148bcdc6a3bSJan Kneschke return NULL; 149bcdc6a3bSJan Kneschke } 150bcdc6a3bSJan Kneschke 15186bb8be2SGlenn Strauss data_unset *array_extract_element_klen(array *a, const char *key, size_t klen) { 15268e4a416SStefan Bühler size_t ndx, pos; 15368e4a416SStefan Bühler force_assert(NULL != key); 15468e4a416SStefan Bühler 15586bb8be2SGlenn Strauss if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, &pos))) { 15668e4a416SStefan Bühler /* found */ 15768e4a416SStefan Bühler const size_t last_ndx = a->used - 1; 15868e4a416SStefan Bühler data_unset *entry = a->data[ndx]; 15968e4a416SStefan Bühler 16068e4a416SStefan Bühler /* now we need to swap it with the last element (if it isn't already the last element) */ 16168e4a416SStefan Bühler if (ndx != last_ndx) { 16268e4a416SStefan Bühler /* to swap we also need to modify the index in a->sorted - find pos of last_elem there */ 16368e4a416SStefan Bühler size_t last_elem_pos; 16468e4a416SStefan Bühler /* last element must be present at the expected position */ 16568e4a416SStefan Bühler force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos)); 16668e4a416SStefan Bühler 16768e4a416SStefan Bühler /* move entry from last_ndx to ndx */ 16868e4a416SStefan Bühler a->data[ndx] = a->data[last_ndx]; 16968e4a416SStefan Bühler a->data[last_ndx] = NULL; 17068e4a416SStefan Bühler 17168e4a416SStefan Bühler /* fix index entry for moved entry */ 17268e4a416SStefan Bühler a->sorted[last_elem_pos] = ndx; 17368e4a416SStefan Bühler } else { 17468e4a416SStefan Bühler a->data[ndx] = NULL; 17568e4a416SStefan Bühler } 17668e4a416SStefan Bühler 17768e4a416SStefan Bühler /* remove entry in a->sorted: move everything after pos one step to the left */ 17868e4a416SStefan Bühler if (pos != last_ndx) { 17968e4a416SStefan Bühler memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted)); 18068e4a416SStefan Bühler } 18168e4a416SStefan Bühler a->sorted[last_ndx] = ARRAY_NOT_FOUND; 18268e4a416SStefan Bühler --a->used; 18368e4a416SStefan Bühler 18468e4a416SStefan Bühler return entry; 18568e4a416SStefan Bühler } 18668e4a416SStefan Bühler 18768e4a416SStefan Bühler return NULL; 18868e4a416SStefan Bühler } 18968e4a416SStefan Bühler 190a7c27c9fSGlenn Strauss static data_unset *array_get_unused_element(array *a, data_type_t t) { 191bcdc6a3bSJan Kneschke data_unset *ds = NULL; 19212f375f3SStefan Bühler unsigned int i; 193bcdc6a3bSJan Kneschke 19412f375f3SStefan Bühler for (i = a->used; i < a->size; i++) { 19512f375f3SStefan Bühler if (a->data[i] && a->data[i]->type == t) { 19612f375f3SStefan Bühler ds = a->data[i]; 197bcdc6a3bSJan Kneschke 19812f375f3SStefan Bühler /* make empty slot at a->used for next insert */ 19912f375f3SStefan Bühler a->data[i] = a->data[a->used]; 200bcdc6a3bSJan Kneschke a->data[a->used] = NULL; 201bcdc6a3bSJan Kneschke 202bcdc6a3bSJan Kneschke return ds; 203bcdc6a3bSJan Kneschke } 20412f375f3SStefan Bühler } 20512f375f3SStefan Bühler 20612f375f3SStefan Bühler return NULL; 20712f375f3SStefan Bühler } 208bcdc6a3bSJan Kneschke 2094f4d40f3SStefan Bühler void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 210a7c27c9fSGlenn Strauss data_string *ds; 2114f4d40f3SStefan Bühler 212a7c27c9fSGlenn Strauss if (NULL != (ds = (data_string *)array_get_element_klen(hdrs, key, key_len))) { 213a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 2144f4d40f3SStefan Bühler return; 2154f4d40f3SStefan Bühler } 2164f4d40f3SStefan Bühler 217a7c27c9fSGlenn Strauss array_insert_key_value(hdrs, key, key_len, value, val_len); 2184f4d40f3SStefan Bühler } 2194f4d40f3SStefan Bühler 220a7c27c9fSGlenn Strauss void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) { 221a7c27c9fSGlenn Strauss data_string *ds; 222a7c27c9fSGlenn Strauss 223a7c27c9fSGlenn Strauss if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 224a7c27c9fSGlenn Strauss ds = data_string_init(); 225a7c27c9fSGlenn Strauss } 226a7c27c9fSGlenn Strauss 227a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->key, key, key_len); 228a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 229a7c27c9fSGlenn Strauss array_insert_unique(hdrs, (data_unset *)ds); 230a7c27c9fSGlenn Strauss } 231a7c27c9fSGlenn Strauss 232a7c27c9fSGlenn Strauss void array_insert_value(array *hdrs, const char *value, size_t val_len) { 233a7c27c9fSGlenn Strauss data_string *ds; 234a7c27c9fSGlenn Strauss 235a7c27c9fSGlenn Strauss if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) { 236a7c27c9fSGlenn Strauss ds = data_string_init(); 237a7c27c9fSGlenn Strauss } 238a7c27c9fSGlenn Strauss 239a7c27c9fSGlenn Strauss buffer_copy_string_len(ds->value, value, val_len); 240a7c27c9fSGlenn Strauss array_insert_unique(hdrs, (data_unset *)ds); 2414f4d40f3SStefan Bühler } 2424f4d40f3SStefan Bühler 243002a4c52SGlenn Strauss int * array_get_int_ptr(array *a, const char *k, size_t klen) { 244002a4c52SGlenn Strauss data_integer *di = (data_integer *)array_get_element_klen(a, k, klen); 245002a4c52SGlenn Strauss 246002a4c52SGlenn Strauss if (NULL == di) { 247002a4c52SGlenn Strauss di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER); 248002a4c52SGlenn Strauss if (NULL == di) di = data_integer_init(); 249002a4c52SGlenn Strauss buffer_copy_string_len(di->key, k, klen); 250002a4c52SGlenn Strauss array_insert_unique(a, (data_unset *)di); 251002a4c52SGlenn Strauss } 252002a4c52SGlenn Strauss 253002a4c52SGlenn Strauss return &di->value; 254002a4c52SGlenn Strauss } 255002a4c52SGlenn Strauss 2568d8ae9cbSStefan Bühler /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */ 257be121a63SStefan Bühler static data_unset **array_find_or_insert(array *a, data_unset *entry) { 258224bf545SStefan Bühler size_t ndx, pos, j; 259bcdc6a3bSJan Kneschke 260bcdc6a3bSJan Kneschke /* generate unique index if neccesary */ 261be121a63SStefan Bühler if (buffer_is_empty(entry->key) || entry->is_index_key) { 262be121a63SStefan Bühler buffer_copy_int(entry->key, a->unique_ndx++); 263be121a63SStefan Bühler entry->is_index_key = 1; 2648d8ae9cbSStefan Bühler force_assert(0 != a->unique_ndx); /* must not wrap or we'll get problems */ 265bcdc6a3bSJan Kneschke } 266bcdc6a3bSJan Kneschke 267be121a63SStefan Bühler /* try to find the entry */ 268224bf545SStefan Bühler if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, CONST_BUF_LEN(entry->key), &pos))) { 2698d8ae9cbSStefan Bühler /* found collision, return it */ 2708d8ae9cbSStefan Bühler return &a->data[ndx]; 271bcdc6a3bSJan Kneschke } 272bcdc6a3bSJan Kneschke 273bcdc6a3bSJan Kneschke /* insert */ 274bcdc6a3bSJan Kneschke 275224bf545SStefan Bühler /* there couldn't possibly be enough memory to store so many entries */ 276224bf545SStefan Bühler force_assert(a->used + 1 <= SSIZE_MAX); 277bcdc6a3bSJan Kneschke 278*d28bac32SGlenn Strauss if (a->size == a->used) { 279bcdc6a3bSJan Kneschke a->size += 16; 280bcdc6a3bSJan Kneschke a->data = realloc(a->data, sizeof(*a->data) * a->size); 281bcdc6a3bSJan Kneschke a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size); 28207dd0bd0SStefan Bühler force_assert(a->data); 28307dd0bd0SStefan Bühler force_assert(a->sorted); 284bcdc6a3bSJan Kneschke for (j = a->used; j < a->size; j++) a->data[j] = NULL; 285bcdc6a3bSJan Kneschke } 286bcdc6a3bSJan Kneschke 287224bf545SStefan Bühler ndx = a->used; 288bcdc6a3bSJan Kneschke 28912f375f3SStefan Bühler /* make sure there is nothing here */ 2908c7f1dfbSGlenn Strauss if (a->data[ndx]) a->data[ndx]->fn->free(a->data[ndx]); 29112f375f3SStefan Bühler 292be121a63SStefan Bühler a->data[a->used++] = entry; 293bcdc6a3bSJan Kneschke 2948d8ae9cbSStefan Bühler /* move everything one step to the right */ 295bcdc6a3bSJan Kneschke if (pos != ndx) { 296bcdc6a3bSJan Kneschke memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted)); 297bcdc6a3bSJan Kneschke } 298bcdc6a3bSJan Kneschke 299bcdc6a3bSJan Kneschke /* insert */ 300bcdc6a3bSJan Kneschke a->sorted[pos] = ndx; 301bcdc6a3bSJan Kneschke 3028d8ae9cbSStefan Bühler return NULL; 3038d8ae9cbSStefan Bühler } 3048d8ae9cbSStefan Bühler 3058d8ae9cbSStefan Bühler /* replace or insert data (free existing entry) */ 3068d8ae9cbSStefan Bühler void array_replace(array *a, data_unset *entry) { 3078d8ae9cbSStefan Bühler data_unset **old; 3088d8ae9cbSStefan Bühler 3098d8ae9cbSStefan Bühler force_assert(NULL != entry); 3108d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) { 3118d8ae9cbSStefan Bühler force_assert(*old != entry); 3128c7f1dfbSGlenn Strauss (*old)->fn->free(*old); 3138d8ae9cbSStefan Bühler *old = entry; 3148d8ae9cbSStefan Bühler } 3158d8ae9cbSStefan Bühler } 3168d8ae9cbSStefan Bühler 3178d8ae9cbSStefan Bühler void array_insert_unique(array *a, data_unset *entry) { 3188d8ae9cbSStefan Bühler data_unset **old; 3198d8ae9cbSStefan Bühler 3208d8ae9cbSStefan Bühler force_assert(NULL != entry); 3218d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) { 3228d8ae9cbSStefan Bühler force_assert((*old)->type == entry->type); 3238c7f1dfbSGlenn Strauss entry->fn->insert_dup(*old, entry); 3248d8ae9cbSStefan Bühler } 325bcdc6a3bSJan Kneschke } 326bcdc6a3bSJan Kneschke 327bd77abe0SGlenn Strauss int array_is_vlist(array *a) { 328bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 329bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 330bd77abe0SGlenn Strauss if (!du->is_index_key || du->type != TYPE_STRING) return 0; 331bd77abe0SGlenn Strauss } 332bd77abe0SGlenn Strauss return 1; 333bd77abe0SGlenn Strauss } 334bd77abe0SGlenn Strauss 335bd77abe0SGlenn Strauss int array_is_kvany(array *a) { 336bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 337bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 338bd77abe0SGlenn Strauss if (du->is_index_key) return 0; 339bd77abe0SGlenn Strauss } 340bd77abe0SGlenn Strauss return 1; 341bd77abe0SGlenn Strauss } 342bd77abe0SGlenn Strauss 343bd77abe0SGlenn Strauss int array_is_kvarray(array *a) { 344bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 345bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 346bd77abe0SGlenn Strauss if (du->is_index_key || du->type != TYPE_ARRAY) return 0; 347bd77abe0SGlenn Strauss } 348bd77abe0SGlenn Strauss return 1; 349bd77abe0SGlenn Strauss } 350bd77abe0SGlenn Strauss 351bd77abe0SGlenn Strauss int array_is_kvstring(array *a) { 352bd77abe0SGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 353bd77abe0SGlenn Strauss data_unset *du = a->data[i]; 354bd77abe0SGlenn Strauss if (du->is_index_key || du->type != TYPE_STRING) return 0; 355bd77abe0SGlenn Strauss } 356bd77abe0SGlenn Strauss return 1; 357bd77abe0SGlenn Strauss } 358bd77abe0SGlenn Strauss 359e6741acdSGlenn Strauss /* array_match_*() routines follow very similar pattern, but operate on slightly 360e6741acdSGlenn Strauss * different data: array key/value, prefix/suffix match, case-insensitive or not 361e6741acdSGlenn Strauss * While these could be combined into fewer routines with flags to modify the 362e6741acdSGlenn Strauss * behavior, the interface distinctions are useful to add clarity to the code, 363e6741acdSGlenn Strauss * and the specialized routines run slightly faster */ 364e6741acdSGlenn Strauss 365e6741acdSGlenn Strauss data_unset * 366e6741acdSGlenn Strauss array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen) 367e6741acdSGlenn Strauss { 368e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 369e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 370e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 371e6741acdSGlenn Strauss if (klen <= slen && 0 == memcmp(s, key->ptr, klen)) 372e6741acdSGlenn Strauss return a->data[i]; 373e6741acdSGlenn Strauss } 374e6741acdSGlenn Strauss return NULL; 375e6741acdSGlenn Strauss } 376e6741acdSGlenn Strauss 377e6741acdSGlenn Strauss data_unset * 378e6741acdSGlenn Strauss array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen) 379e6741acdSGlenn Strauss { 380e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 381e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 382e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 383e6741acdSGlenn Strauss if (klen <= slen && 0 == strncasecmp(s, key->ptr, klen)) 384e6741acdSGlenn Strauss return a->data[i]; 385e6741acdSGlenn Strauss } 386e6741acdSGlenn Strauss return NULL; 387e6741acdSGlenn Strauss } 388e6741acdSGlenn Strauss 389e6741acdSGlenn Strauss data_unset * 390e6741acdSGlenn Strauss array_match_key_prefix (const array * const a, const buffer * const b) 391e6741acdSGlenn Strauss { 392e6741acdSGlenn Strauss return array_match_key_prefix_klen(a, CONST_BUF_LEN(b)); 393e6741acdSGlenn Strauss } 394e6741acdSGlenn Strauss 395e6741acdSGlenn Strauss data_unset * 396e6741acdSGlenn Strauss array_match_key_prefix_nc (const array * const a, const buffer * const b) 397e6741acdSGlenn Strauss { 398e6741acdSGlenn Strauss return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b)); 399e6741acdSGlenn Strauss } 400e6741acdSGlenn Strauss 401e6741acdSGlenn Strauss const buffer * 402e6741acdSGlenn Strauss array_match_value_prefix (const array * const a, const buffer * const b) 403e6741acdSGlenn Strauss { 404e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 405e6741acdSGlenn Strauss 406e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 407e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 408e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 409e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen)) 410e6741acdSGlenn Strauss return value; 411e6741acdSGlenn Strauss } 412e6741acdSGlenn Strauss return NULL; 413e6741acdSGlenn Strauss } 414e6741acdSGlenn Strauss 415e6741acdSGlenn Strauss const buffer * 416e6741acdSGlenn Strauss array_match_value_prefix_nc (const array * const a, const buffer * const b) 417e6741acdSGlenn Strauss { 418e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 419e6741acdSGlenn Strauss 420e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 421e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 422e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 423e6741acdSGlenn Strauss if (vlen <= blen && 0 == strncasecmp(b->ptr, value->ptr, vlen)) 424e6741acdSGlenn Strauss return value; 425e6741acdSGlenn Strauss } 426e6741acdSGlenn Strauss return NULL; 427e6741acdSGlenn Strauss } 428e6741acdSGlenn Strauss 429e6741acdSGlenn Strauss data_unset * 430e6741acdSGlenn Strauss array_match_key_suffix (const array * const a, const buffer * const b) 431e6741acdSGlenn Strauss { 432e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 433e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 434e6741acdSGlenn Strauss 435e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 436e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 437e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 438e6741acdSGlenn Strauss if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen)) 439e6741acdSGlenn Strauss return a->data[i]; 440e6741acdSGlenn Strauss } 441e6741acdSGlenn Strauss return NULL; 442e6741acdSGlenn Strauss } 443e6741acdSGlenn Strauss 444e6741acdSGlenn Strauss data_unset * 445e6741acdSGlenn Strauss array_match_key_suffix_nc (const array * const a, const buffer * const b) 446e6741acdSGlenn Strauss { 447e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 448e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 449e6741acdSGlenn Strauss 450e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 451e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 452e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 453e6741acdSGlenn Strauss if (klen <= blen && 0 == strncasecmp(end - klen, key->ptr, klen)) 454e6741acdSGlenn Strauss return a->data[i]; 455e6741acdSGlenn Strauss } 456e6741acdSGlenn Strauss return NULL; 457e6741acdSGlenn Strauss } 458e6741acdSGlenn Strauss 459e6741acdSGlenn Strauss const buffer * 460e6741acdSGlenn Strauss array_match_value_suffix (const array * const a, const buffer * const b) 461e6741acdSGlenn Strauss { 462e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 463e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 464e6741acdSGlenn Strauss 465e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 466e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 467e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 468e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen)) 469e6741acdSGlenn Strauss return value; 470e6741acdSGlenn Strauss } 471e6741acdSGlenn Strauss return NULL; 472e6741acdSGlenn Strauss } 473e6741acdSGlenn Strauss 474e6741acdSGlenn Strauss const buffer * 475e6741acdSGlenn Strauss array_match_value_suffix_nc (const array * const a, const buffer * const b) 476e6741acdSGlenn Strauss { 477e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 478e6741acdSGlenn Strauss const char * const end = b->ptr + blen; 479e6741acdSGlenn Strauss 480e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 481e6741acdSGlenn Strauss const buffer * const value = ((data_string *)a->data[i])->value; 482e6741acdSGlenn Strauss const size_t vlen = buffer_string_length(value); 483e6741acdSGlenn Strauss if (vlen <= blen && 0 == strncasecmp(end - vlen, value->ptr, vlen)) 484e6741acdSGlenn Strauss return value; 485e6741acdSGlenn Strauss } 486e6741acdSGlenn Strauss return NULL; 487e6741acdSGlenn Strauss } 488e6741acdSGlenn Strauss 489e6741acdSGlenn Strauss data_unset * 490e6741acdSGlenn Strauss array_match_path_or_ext (const array * const a, const buffer * const b) 491e6741acdSGlenn Strauss { 492e6741acdSGlenn Strauss const size_t blen = buffer_string_length(b); 493e6741acdSGlenn Strauss 494e6741acdSGlenn Strauss for (size_t i = 0; i < a->used; ++i) { 495e6741acdSGlenn Strauss /* check extension in the form "^/path" or ".ext$" */ 496e6741acdSGlenn Strauss const buffer * const key = a->data[i]->key; 497e6741acdSGlenn Strauss const size_t klen = buffer_string_length(key); 498e6741acdSGlenn Strauss if (klen <= blen 499e6741acdSGlenn Strauss && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen), 500e6741acdSGlenn Strauss key->ptr, klen)) 501e6741acdSGlenn Strauss return a->data[i]; 502e6741acdSGlenn Strauss } 503e6741acdSGlenn Strauss return NULL; 504e6741acdSGlenn Strauss } 505e6741acdSGlenn Strauss 506e6741acdSGlenn Strauss 507e6741acdSGlenn Strauss 508a46bc4f5SGlenn Strauss 509a46bc4f5SGlenn Strauss 510a46bc4f5SGlenn Strauss #include <stdio.h> 511a46bc4f5SGlenn Strauss 5129e75ba00SJan Kneschke void array_print_indent(int depth) { 5139e75ba00SJan Kneschke int i; 5149e75ba00SJan Kneschke for (i = 0; i < depth; i ++) { 515dd0abe5aSJan Kneschke fprintf(stdout, " "); 5169e75ba00SJan Kneschke } 5179e75ba00SJan Kneschke } 5189e75ba00SJan Kneschke 5196044dbc5SmOo size_t array_get_max_key_length(array *a) { 5206044dbc5SmOo size_t maxlen, i; 5216044dbc5SmOo 5226044dbc5SmOo maxlen = 0; 5236044dbc5SmOo for (i = 0; i < a->used; i ++) { 5246044dbc5SmOo data_unset *du = a->data[i]; 52586bb8be2SGlenn Strauss size_t len = buffer_string_length(du->key); 5266044dbc5SmOo 5276044dbc5SmOo if (len > maxlen) { 5286044dbc5SmOo maxlen = len; 5296044dbc5SmOo } 5306044dbc5SmOo } 5316044dbc5SmOo return maxlen; 5326044dbc5SmOo } 5336044dbc5SmOo 5349e75ba00SJan Kneschke int array_print(array *a, int depth) { 535bcdc6a3bSJan Kneschke size_t i; 5366044dbc5SmOo size_t maxlen; 5376044dbc5SmOo int oneline = 1; 538bcdc6a3bSJan Kneschke 5396044dbc5SmOo if (a->used > 5) { 5406044dbc5SmOo oneline = 0; 5416044dbc5SmOo } 5426044dbc5SmOo for (i = 0; i < a->used && oneline; i++) { 5436044dbc5SmOo data_unset *du = a->data[i]; 544f387d898SmOo if (!du->is_index_key) { 5456044dbc5SmOo oneline = 0; 5466044dbc5SmOo break; 5476044dbc5SmOo } 5486044dbc5SmOo switch (du->type) { 5496044dbc5SmOo case TYPE_INTEGER: 5506044dbc5SmOo case TYPE_STRING: 5516044dbc5SmOo break; 5526044dbc5SmOo default: 5536044dbc5SmOo oneline = 0; 5546044dbc5SmOo break; 5556044dbc5SmOo } 5566044dbc5SmOo } 5576044dbc5SmOo if (oneline) { 558dd0abe5aSJan Kneschke fprintf(stdout, "("); 559bcdc6a3bSJan Kneschke for (i = 0; i < a->used; i++) { 5606044dbc5SmOo data_unset *du = a->data[i]; 5616044dbc5SmOo if (i != 0) { 562dd0abe5aSJan Kneschke fprintf(stdout, ", "); 5636044dbc5SmOo } 5648c7f1dfbSGlenn Strauss du->fn->print(du, depth + 1); 5656044dbc5SmOo } 566dd0abe5aSJan Kneschke fprintf(stdout, ")"); 5676044dbc5SmOo return 0; 5686044dbc5SmOo } 5696044dbc5SmOo 5706044dbc5SmOo maxlen = array_get_max_key_length(a); 571dd0abe5aSJan Kneschke fprintf(stdout, "(\n"); 5726044dbc5SmOo for (i = 0; i < a->used; i++) { 5736044dbc5SmOo data_unset *du = a->data[i]; 5748b07d57dSJan Kneschke array_print_indent(depth + 1); 575f387d898SmOo if (!du->is_index_key) { 5766044dbc5SmOo int j; 5776044dbc5SmOo 5786044dbc5SmOo if (i && (i % 5) == 0) { 579acad2c90SGlenn Strauss fprintf(stdout, "# %zu\n", i); 5806044dbc5SmOo array_print_indent(depth + 1); 5816044dbc5SmOo } 582dd0abe5aSJan Kneschke fprintf(stdout, "\"%s\"", du->key->ptr); 58386bb8be2SGlenn Strauss for (j = maxlen - buffer_string_length(du->key); j > 0; j--) { 584dd0abe5aSJan Kneschke fprintf(stdout, " "); 5856044dbc5SmOo } 586dd0abe5aSJan Kneschke fprintf(stdout, " => "); 5876044dbc5SmOo } 5888c7f1dfbSGlenn Strauss du->fn->print(du, depth + 1); 589dd0abe5aSJan Kneschke fprintf(stdout, ",\n"); 5906044dbc5SmOo } 5916044dbc5SmOo if (!(i && (i - 1 % 5) == 0)) { 5926044dbc5SmOo array_print_indent(depth + 1); 593acad2c90SGlenn Strauss fprintf(stdout, "# %zu\n", i); 594bcdc6a3bSJan Kneschke } 5958b07d57dSJan Kneschke array_print_indent(depth); 596dd0abe5aSJan Kneschke fprintf(stdout, ")"); 597bcdc6a3bSJan Kneschke 598bcdc6a3bSJan Kneschke return 0; 599bcdc6a3bSJan Kneschke } 600