18abd06a7SGlenn Strauss #include "first.h"
28abd06a7SGlenn Strauss
322e8b456SStefan Bühler #include "array.h"
422e8b456SStefan Bühler #include "buffer.h"
5*5e14db43SGlenn Strauss #include "ck.h"
622e8b456SStefan Bühler
7bcdc6a3bSJan Kneschke #include <string.h>
8bcdc6a3bSJan Kneschke #include <stdlib.h>
9bcdc6a3bSJan Kneschke #include <limits.h>
10bcdc6a3bSJan Kneschke
114f8f83eaSGlenn Strauss
124f8f83eaSGlenn Strauss __attribute_cold__
array_data_string_copy(const data_unset * s)134f8f83eaSGlenn Strauss static data_unset *array_data_string_copy(const data_unset *s) {
144f8f83eaSGlenn Strauss data_string *src = (data_string *)s;
154f8f83eaSGlenn Strauss data_string *ds = array_data_string_init();
16af3df29aSGlenn Strauss if (!buffer_is_unset(&src->key)) buffer_copy_buffer(&ds->key, &src->key);
174f8f83eaSGlenn Strauss buffer_copy_buffer(&ds->value, &src->value);
184f8f83eaSGlenn Strauss return (data_unset *)ds;
194f8f83eaSGlenn Strauss }
204f8f83eaSGlenn Strauss
214f8f83eaSGlenn Strauss __attribute_cold__
array_data_string_insert_dup(data_unset * dst,data_unset * src)224f8f83eaSGlenn Strauss static void array_data_string_insert_dup(data_unset *dst, data_unset *src) {
234f8f83eaSGlenn Strauss data_string *ds_dst = (data_string *)dst;
244f8f83eaSGlenn Strauss data_string *ds_src = (data_string *)src;
25af3df29aSGlenn Strauss if (!buffer_is_blank(&ds_dst->value))
264f8f83eaSGlenn Strauss buffer_append_str2(&ds_dst->value, CONST_STR_LEN(", "),
27af3df29aSGlenn Strauss BUF_PTR_LEN(&ds_src->value));
284f8f83eaSGlenn Strauss else
294f8f83eaSGlenn Strauss buffer_copy_buffer(&ds_dst->value, &ds_src->value);
304f8f83eaSGlenn Strauss }
314f8f83eaSGlenn Strauss
array_data_string_free(data_unset * du)324f8f83eaSGlenn Strauss static void array_data_string_free(data_unset *du) {
334f8f83eaSGlenn Strauss data_string *ds = (data_string *)du;
344f8f83eaSGlenn Strauss free(ds->key.ptr);
354f8f83eaSGlenn Strauss free(ds->value.ptr);
364f8f83eaSGlenn Strauss free(ds);
374f8f83eaSGlenn Strauss }
384f8f83eaSGlenn Strauss
394f8f83eaSGlenn Strauss __attribute_noinline__
array_data_string_init(void)404f8f83eaSGlenn Strauss data_string *array_data_string_init(void) {
41ae2fb974SStefan Bühler static const struct data_methods string_fn = {
424f8f83eaSGlenn Strauss array_data_string_copy,
434f8f83eaSGlenn Strauss array_data_string_free,
444f8f83eaSGlenn Strauss array_data_string_insert_dup,
454f8f83eaSGlenn Strauss };
46*5e14db43SGlenn Strauss data_string *ds = ck_calloc(1, sizeof(*ds));
474f8f83eaSGlenn Strauss ds->type = TYPE_STRING;
48ae2fb974SStefan Bühler ds->fn = &string_fn;
494f8f83eaSGlenn Strauss return ds;
504f8f83eaSGlenn Strauss }
514f8f83eaSGlenn Strauss
524f8f83eaSGlenn Strauss
534f8f83eaSGlenn Strauss __attribute_cold__
array_data_integer_copy(const data_unset * s)544f8f83eaSGlenn Strauss static data_unset *array_data_integer_copy(const data_unset *s) {
554f8f83eaSGlenn Strauss data_integer *src = (data_integer *)s;
564f8f83eaSGlenn Strauss data_integer *di = array_data_integer_init();
57af3df29aSGlenn Strauss if (!buffer_is_unset(&src->key)) buffer_copy_buffer(&di->key, &src->key);
584f8f83eaSGlenn Strauss di->value = src->value;
594f8f83eaSGlenn Strauss return (data_unset *)di;
604f8f83eaSGlenn Strauss }
614f8f83eaSGlenn Strauss
array_data_integer_free(data_unset * du)624f8f83eaSGlenn Strauss static void array_data_integer_free(data_unset *du) {
634f8f83eaSGlenn Strauss data_integer *di = (data_integer *)du;
644f8f83eaSGlenn Strauss free(di->key.ptr);
654f8f83eaSGlenn Strauss free(di);
664f8f83eaSGlenn Strauss }
674f8f83eaSGlenn Strauss
684f8f83eaSGlenn Strauss __attribute_noinline__
array_data_integer_init(void)694f8f83eaSGlenn Strauss data_integer *array_data_integer_init(void) {
70ae2fb974SStefan Bühler static const struct data_methods integer_fn = {
714f8f83eaSGlenn Strauss array_data_integer_copy,
724f8f83eaSGlenn Strauss array_data_integer_free,
73cc8e7107SGlenn Strauss NULL
744f8f83eaSGlenn Strauss };
75*5e14db43SGlenn Strauss data_integer *di = ck_calloc(1, sizeof(*di));
764f8f83eaSGlenn Strauss di->type = TYPE_INTEGER;
77ae2fb974SStefan Bühler di->fn = &integer_fn;
784f8f83eaSGlenn Strauss return di;
794f8f83eaSGlenn Strauss }
804f8f83eaSGlenn Strauss
814f8f83eaSGlenn Strauss
824f8f83eaSGlenn Strauss __attribute_cold__
array_data_array_copy(const data_unset * s)834f8f83eaSGlenn Strauss static data_unset *array_data_array_copy(const data_unset *s) {
844f8f83eaSGlenn Strauss data_array *src = (data_array *)s;
854f8f83eaSGlenn Strauss data_array *da = array_data_array_init();
86af3df29aSGlenn Strauss if (!buffer_is_unset(&src->key)) buffer_copy_buffer(&da->key, &src->key);
874f8f83eaSGlenn Strauss array_copy_array(&da->value, &src->value);
884f8f83eaSGlenn Strauss return (data_unset *)da;
894f8f83eaSGlenn Strauss }
904f8f83eaSGlenn Strauss
array_data_array_free(data_unset * du)914f8f83eaSGlenn Strauss static void array_data_array_free(data_unset *du) {
924f8f83eaSGlenn Strauss data_array *da = (data_array *)du;
934f8f83eaSGlenn Strauss free(da->key.ptr);
944f8f83eaSGlenn Strauss array_free_data(&da->value);
954f8f83eaSGlenn Strauss free(da);
964f8f83eaSGlenn Strauss }
974f8f83eaSGlenn Strauss
984f8f83eaSGlenn Strauss __attribute_noinline__
array_data_array_init(void)994f8f83eaSGlenn Strauss data_array *array_data_array_init(void) {
100ae2fb974SStefan Bühler static const struct data_methods array_fn = {
1014f8f83eaSGlenn Strauss array_data_array_copy,
1024f8f83eaSGlenn Strauss array_data_array_free,
103cc8e7107SGlenn Strauss NULL
1044f8f83eaSGlenn Strauss };
105*5e14db43SGlenn Strauss data_array *da = ck_calloc(1, sizeof(*da));
1064f8f83eaSGlenn Strauss da->type = TYPE_ARRAY;
107ae2fb974SStefan Bühler da->fn = &array_fn;
1084f8f83eaSGlenn Strauss return da;
1094f8f83eaSGlenn Strauss }
1104f8f83eaSGlenn Strauss
1114f8f83eaSGlenn Strauss
112b2991c68SGlenn Strauss __attribute_cold__
array_extend(array * const a,uint32_t n)11324680a91SGlenn Strauss static void array_extend(array * const a, uint32_t n) {
11430edc55bSGlenn Strauss /* This data structure should not be used for nearly so many entries */
11530edc55bSGlenn Strauss force_assert(a->size <= INT32_MAX-n);
11624680a91SGlenn Strauss a->size += n;
117c412bb59SGlenn Strauss a->data = ck_realloc_u32((void**)&a->data, a->size,0,sizeof(*a->data));
118c412bb59SGlenn Strauss a->sorted = ck_realloc_u32((void**)&a->sorted,a->size,0,sizeof(*a->sorted));
119b2991c68SGlenn Strauss memset(a->data+a->used, 0, (a->size-a->used)*sizeof(*a->data));
120b2991c68SGlenn Strauss }
121224bf545SStefan Bühler
array_init(uint32_t n)12224680a91SGlenn Strauss array *array_init(uint32_t n) {
123*5e14db43SGlenn Strauss array *a = ck_calloc(1, sizeof(*a));
12424680a91SGlenn Strauss if (n) array_extend(a, n);
125bcdc6a3bSJan Kneschke return a;
126bcdc6a3bSJan Kneschke }
127bcdc6a3bSJan Kneschke
array_free_data(array * const a)128c2238256SGlenn Strauss void array_free_data(array * const a) {
129a762402dSGlenn Strauss if (a->sorted) free(a->sorted);
130b2991c68SGlenn Strauss data_unset ** const data = a->data;
131b2991c68SGlenn Strauss const uint32_t sz = a->size;
132b2991c68SGlenn Strauss for (uint32_t i = 0; i < sz; ++i) {
133b2991c68SGlenn Strauss if (data[i]) data[i]->fn->free(data[i]);
134bcdc6a3bSJan Kneschke }
135c2238256SGlenn Strauss free(data);
136f24e6d69SGlenn Strauss a->data = NULL;
137f24e6d69SGlenn Strauss a->sorted = NULL;
138f24e6d69SGlenn Strauss a->used = 0;
139f24e6d69SGlenn Strauss a->size = 0;
140c2238256SGlenn Strauss }
141bcdc6a3bSJan Kneschke
array_copy_array(array * const dst,const array * const src)142c2238256SGlenn Strauss void array_copy_array(array * const dst, const array * const src) {
143c2238256SGlenn Strauss array_free_data(dst);
144c2238256SGlenn Strauss if (0 == src->size) return;
145c2238256SGlenn Strauss
146fefdf7f0SGlenn Strauss array_extend(dst, src->size);
147c2238256SGlenn Strauss for (uint32_t i = 0; i < src->used; ++i) {
148fefdf7f0SGlenn Strauss array_insert_unique(dst, src->data[i]->fn->copy(src->data[i]));
149c2238256SGlenn Strauss }
150c2238256SGlenn Strauss }
151c2238256SGlenn Strauss
array_free(array * const a)152c2238256SGlenn Strauss void array_free(array * const a) {
153c2238256SGlenn Strauss if (!a) return;
154c2238256SGlenn Strauss array_free_data(a);
155bcdc6a3bSJan Kneschke free(a);
156bcdc6a3bSJan Kneschke }
157bcdc6a3bSJan Kneschke
array_reset_data_strings(array * const a)158b2991c68SGlenn Strauss void array_reset_data_strings(array * const a) {
159062089ffSGlenn Strauss if (!a) return;
160062089ffSGlenn Strauss
161b2991c68SGlenn Strauss data_string ** const data = (data_string **)a->data;
162b2991c68SGlenn Strauss const uint32_t used = a->used;
163b2991c68SGlenn Strauss a->used = 0;
164b2991c68SGlenn Strauss for (uint32_t i = 0; i < used; ++i) {
165b2991c68SGlenn Strauss data_string * const ds = data[i];
166062089ffSGlenn Strauss /*force_assert(ds->type == TYPE_STRING);*/
167b600b75fSGlenn Strauss buffer_reset(&ds->key);
168b600b75fSGlenn Strauss buffer_reset(&ds->value);
169b2991c68SGlenn Strauss }
170062089ffSGlenn Strauss }
171062089ffSGlenn Strauss
172b2991c68SGlenn Strauss #if 0 /*(unused; see array_extract_element_klen())*/
173b2991c68SGlenn Strauss data_unset *array_pop(array * const a) {
1748073d5feSJan Kneschke data_unset *du;
1758073d5feSJan Kneschke
17607dd0bd0SStefan Bühler force_assert(a->used != 0);
1778073d5feSJan Kneschke
1788073d5feSJan Kneschke a->used --;
1798073d5feSJan Kneschke du = a->data[a->used];
180e3dc34d1SGlenn Strauss force_assert(a->sorted[a->used] == du); /* only works on "simple" lists */
1818073d5feSJan Kneschke a->data[a->used] = NULL;
1828073d5feSJan Kneschke
1838073d5feSJan Kneschke return du;
1848073d5feSJan Kneschke }
185b2991c68SGlenn Strauss #endif
1868073d5feSJan Kneschke
187ca059d58SGlenn Strauss __attribute_pure__
array_caseless_compare(const char * const a,const char * const b,const uint32_t len)18868ec5ad6SGlenn Strauss static int array_caseless_compare(const char * const a, const char * const b, const uint32_t len) {
18968ec5ad6SGlenn Strauss for (uint32_t i = 0; i < len; ++i) {
190ca059d58SGlenn Strauss unsigned int ca = ((unsigned char *)a)[i];
191ca059d58SGlenn Strauss unsigned int cb = ((unsigned char *)b)[i];
192ca059d58SGlenn Strauss if (ca == cb) continue;
193ca059d58SGlenn Strauss
194ca059d58SGlenn Strauss /* always lowercase for transitive results */
195c58b95f2SGlenn Strauss if (light_isupper(ca)) ca |= 0x20;
196c58b95f2SGlenn Strauss if (light_isupper(cb)) cb |= 0x20;
197ca059d58SGlenn Strauss
198ca059d58SGlenn Strauss if (ca == cb) continue;
199ca059d58SGlenn Strauss return (int)(ca - cb);
200ca059d58SGlenn Strauss }
201ca059d58SGlenn Strauss return 0;
202ca059d58SGlenn Strauss }
203ca059d58SGlenn Strauss
204ca059d58SGlenn Strauss __attribute_pure__
array_keycmp(const char * const a,const uint32_t alen,const char * const b,const uint32_t blen)20568ec5ad6SGlenn Strauss static int array_keycmp(const char * const a, const uint32_t alen, const char * const b, const uint32_t blen) {
206ca059d58SGlenn Strauss return alen < blen ? -1 : alen > blen ? 1 : array_caseless_compare(a, b, blen);
207758174ecSGlenn Strauss }
208758174ecSGlenn Strauss
2092e0676fdSGlenn Strauss __attribute_cold__
2102e0676fdSGlenn Strauss __attribute_pure__
array_keycmpb(const char * const k,const uint32_t klen,const buffer * const b)2112e0676fdSGlenn Strauss static int array_keycmpb(const char * const k, const uint32_t klen, const buffer * const b) {
2122e0676fdSGlenn Strauss /* key is non-empty (0==b->used), though possibly blank (1==b->used)
2132e0676fdSGlenn Strauss * if inserted into key-value array */
2142e0676fdSGlenn Strauss /*force_assert(b && b->used);*/
2152e0676fdSGlenn Strauss return array_keycmp(k, klen, b->ptr, b->used-1);
216af3df29aSGlenn Strauss /*return array_keycmp(k, klen, BUF_PTR_LEN(b));*/
2172e0676fdSGlenn Strauss }
2182e0676fdSGlenn Strauss
2192e0676fdSGlenn Strauss /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[]
2202e0676fdSGlenn Strauss * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[]
2212e0676fdSGlenn Strauss * where the key needs to be inserted (-1 to avoid -0)
2222e0676fdSGlenn Strauss */
2232e0676fdSGlenn Strauss __attribute_hot__
2242e0676fdSGlenn Strauss __attribute_pure__
array_get_index_ext(const array * const a,const int ext,const char * const k,const uint32_t klen)2252e0676fdSGlenn Strauss static int32_t array_get_index_ext(const array * const a, const int ext, const char * const k, const uint32_t klen) {
2262e0676fdSGlenn Strauss /* invariant: [lower-1] < probe < [upper]
2272e0676fdSGlenn Strauss * invariant: 0 <= lower <= upper <= a->used
2282e0676fdSGlenn Strauss */
22957c0859fSGlenn Strauss uint_fast32_t lower = 0, upper = a->used;
2302e0676fdSGlenn Strauss while (lower != upper) {
23157c0859fSGlenn Strauss const uint_fast32_t probe = (lower + upper) / 2;
2322e0676fdSGlenn Strauss const int x = ((data_string *)a->sorted[probe])->ext;
2332e0676fdSGlenn Strauss /* (compare strings only if ext is 0 for both)*/
2342e0676fdSGlenn Strauss const int e = (ext|x)
2352e0676fdSGlenn Strauss ? ext
2362e0676fdSGlenn Strauss : array_keycmpb(k, klen, &a->sorted[probe]->key);
2372e0676fdSGlenn Strauss if (e < x) /* e < [probe] */
2382e0676fdSGlenn Strauss upper = probe; /* still: lower <= upper */
2392e0676fdSGlenn Strauss else if (e > x) /* e > [probe] */
2402e0676fdSGlenn Strauss lower = probe + 1; /* still: lower <= upper */
2412e0676fdSGlenn Strauss else /*(e == x)*/ /* found */
2422e0676fdSGlenn Strauss return (int32_t)probe;
2432e0676fdSGlenn Strauss }
2442e0676fdSGlenn Strauss /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */
2452e0676fdSGlenn Strauss return -(int)lower - 1;
2462e0676fdSGlenn Strauss }
2472e0676fdSGlenn Strauss
array_get_element_klen_ext(const array * const a,const int ext,const char * key,const uint32_t klen)2482e0676fdSGlenn Strauss data_unset *array_get_element_klen_ext(const array * const a, const int ext, const char *key, const uint32_t klen) {
2492e0676fdSGlenn Strauss const int32_t ipos = array_get_index_ext(a, ext, key, klen);
2502e0676fdSGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL;
2512e0676fdSGlenn Strauss }
2522e0676fdSGlenn Strauss
253e3dc34d1SGlenn Strauss /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[]
254a762402dSGlenn Strauss * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[]
255a762402dSGlenn Strauss * where the key needs to be inserted (-1 to avoid -0)
256224bf545SStefan Bühler */
257b2991c68SGlenn Strauss __attribute_hot__
258b2991c68SGlenn Strauss __attribute_pure__
array_get_index(const array * const a,const char * const k,const uint32_t klen)25968ec5ad6SGlenn Strauss static int32_t array_get_index(const array * const a, const char * const k, const uint32_t klen) {
260b2991c68SGlenn Strauss /* invariant: [lower-1] < probe < [upper]
261b2991c68SGlenn Strauss * invariant: 0 <= lower <= upper <= a->used
262224bf545SStefan Bühler */
26357c0859fSGlenn Strauss uint_fast32_t lower = 0, upper = a->used;
264224bf545SStefan Bühler while (lower != upper) {
26557c0859fSGlenn Strauss uint_fast32_t probe = (lower + upper) / 2;
266e3dc34d1SGlenn Strauss const buffer * const b = &a->sorted[probe]->key;
26761785d86SGlenn Strauss /* key is non-empty (0==b->used), though possibly blank (1==b->used),
26861785d86SGlenn Strauss * if inserted into key-value array */
26961785d86SGlenn Strauss /*force_assert(b && b->used);*/
27061785d86SGlenn Strauss int cmp = array_keycmp(k, klen, b->ptr, b->used-1);
271af3df29aSGlenn Strauss /*int cmp = array_keycmp(k, klen, BUF_PTR_LEN(b));*/
272b2991c68SGlenn Strauss if (cmp < 0) /* key < [probe] */
273224bf545SStefan Bühler upper = probe; /* still: lower <= upper */
274b2991c68SGlenn Strauss else if (cmp > 0) /* key > [probe] */
275224bf545SStefan Bühler lower = probe + 1; /* still: lower <= upper */
276b2991c68SGlenn Strauss else /*(cmp == 0)*/ /* found */
277b2991c68SGlenn Strauss return (int32_t)probe;
278bcdc6a3bSJan Kneschke }
279224bf545SStefan Bühler /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */
280b2991c68SGlenn Strauss return -(int)lower - 1;
281bcdc6a3bSJan Kneschke }
282bcdc6a3bSJan Kneschke
283b2991c68SGlenn Strauss __attribute_hot__
array_get_element_klen(const array * const a,const char * key,const uint32_t klen)2840045b9aaSGlenn Strauss const data_unset *array_get_element_klen(const array * const a, const char *key, const uint32_t klen) {
28583535bbeSGlenn Strauss const int32_t ipos = array_get_index(a, key, klen);
286e3dc34d1SGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL;
28783535bbeSGlenn Strauss }
28883535bbeSGlenn Strauss
28983535bbeSGlenn Strauss /* non-const (data_config *) for configparser.y (not array_get_element_klen())*/
array_get_data_unset(const array * const a,const char * key,const uint32_t klen)29068ec5ad6SGlenn Strauss data_unset *array_get_data_unset(const array * const a, const char *key, const uint32_t klen) {
291b2991c68SGlenn Strauss const int32_t ipos = array_get_index(a, key, klen);
292e3dc34d1SGlenn Strauss return ipos >= 0 ? a->sorted[ipos] : NULL;
293bcdc6a3bSJan Kneschke }
294bcdc6a3bSJan Kneschke
array_extract_element_klen(array * const a,const char * key,const uint32_t klen)29568ec5ad6SGlenn Strauss data_unset *array_extract_element_klen(array * const a, const char *key, const uint32_t klen) {
296b2991c68SGlenn Strauss const int32_t ipos = array_get_index(a, key, klen);
297b2991c68SGlenn Strauss if (ipos < 0) return NULL;
298bcdc6a3bSJan Kneschke
299e3dc34d1SGlenn Strauss /* remove entry from a->sorted: move everything after pos one step left */
300e3dc34d1SGlenn Strauss data_unset * const entry = a->sorted[ipos];
301c9f1b612SGlenn Strauss const uint32_t last_ndx = --a->used;
302e3dc34d1SGlenn Strauss if (last_ndx != (uint32_t)ipos) {
303e3dc34d1SGlenn Strauss data_unset ** const d = a->sorted + ipos;
304e3dc34d1SGlenn Strauss memmove(d, d+1, (last_ndx - (uint32_t)ipos) * sizeof(*d));
305c9f1b612SGlenn Strauss }
306a762402dSGlenn Strauss
307e3dc34d1SGlenn Strauss if (entry != a->data[last_ndx]) {
308e3dc34d1SGlenn Strauss /* walk a->data[] to find data ptr */
309e3dc34d1SGlenn Strauss /* (not checking (ndx <= last_ndx) since entry must be in a->data[]) */
310e3dc34d1SGlenn Strauss uint32_t ndx = 0;
311e3dc34d1SGlenn Strauss while (entry != a->data[ndx]) ++ndx;
312e3dc34d1SGlenn Strauss a->data[ndx] = a->data[last_ndx]; /* swap with last element */
313a762402dSGlenn Strauss }
31468e4a416SStefan Bühler a->data[last_ndx] = NULL;
31568e4a416SStefan Bühler return entry;
31668e4a416SStefan Bühler }
31768e4a416SStefan Bühler
array_get_unused_element(array * const a,const data_type_t t)318b2991c68SGlenn Strauss static data_unset *array_get_unused_element(array * const a, const data_type_t t) {
319c752d469SGlenn Strauss /* After initial startup and config, most array usage is of homogeneous types
320b2991c68SGlenn Strauss * and arrays are cleared once per request, so check only the first unused
321b2991c68SGlenn Strauss * element to see if it can be reused */
322b2991c68SGlenn Strauss #if 1
323b2991c68SGlenn Strauss data_unset * const du = (a->used < a->size) ? a->data[a->used] : NULL;
324b2991c68SGlenn Strauss if (NULL != du && du->type == t) {
325b2991c68SGlenn Strauss a->data[a->used] = NULL;/* make empty slot at a->used for next insert */
326b2991c68SGlenn Strauss return du;
327b2991c68SGlenn Strauss }
328b2991c68SGlenn Strauss return NULL;
329b2991c68SGlenn Strauss #else
330b2991c68SGlenn Strauss data_unset ** const data = a->data;
331b2991c68SGlenn Strauss for (uint32_t i = a->used, sz = a->size; i < sz; ++i) {
332b2991c68SGlenn Strauss if (data[i] && data[i]->type == t) {
333b2991c68SGlenn Strauss data_unset * const ds = data[i];
334bcdc6a3bSJan Kneschke
33512f375f3SStefan Bühler /* make empty slot at a->used for next insert */
336b2991c68SGlenn Strauss data[i] = data[a->used];
337b2991c68SGlenn Strauss data[a->used] = NULL;
338bcdc6a3bSJan Kneschke
339bcdc6a3bSJan Kneschke return ds;
340bcdc6a3bSJan Kneschke }
34112f375f3SStefan Bühler }
34212f375f3SStefan Bühler
34312f375f3SStefan Bühler return NULL;
344b2991c68SGlenn Strauss #endif
34512f375f3SStefan Bühler }
346bcdc6a3bSJan Kneschke
3472e0676fdSGlenn Strauss __attribute_hot__
array_insert_data_at_pos(array * const a,data_unset * const entry,const uint_fast32_t pos)34841916b58SGlenn Strauss static data_unset * array_insert_data_at_pos(array * const a, data_unset * const entry, const uint_fast32_t pos) {
34930edc55bSGlenn Strauss if (a->used < a->size) {
35030edc55bSGlenn Strauss data_unset * const prev = a->data[a->used];
35130edc55bSGlenn Strauss if (__builtin_expect( (prev != NULL), 0))
35230edc55bSGlenn Strauss prev->fn->free(prev); /* free prior data, if any, from slot */
35330edc55bSGlenn Strauss }
35430edc55bSGlenn Strauss else {
35524680a91SGlenn Strauss array_extend(a, 16);
356bcdc6a3bSJan Kneschke }
357bcdc6a3bSJan Kneschke
35841916b58SGlenn Strauss uint_fast32_t ndx = a->used++;
359a762402dSGlenn Strauss a->data[ndx] = entry;
360bcdc6a3bSJan Kneschke
3618d8ae9cbSStefan Bühler /* move everything one step to the right */
36241916b58SGlenn Strauss ndx -= pos;
363e3dc34d1SGlenn Strauss data_unset ** const d = a->sorted + pos;
36441916b58SGlenn Strauss if (__builtin_expect( (ndx), 1))
36541916b58SGlenn Strauss memmove(d+1, d, ndx * sizeof(*a->sorted));
36641916b58SGlenn Strauss *d = entry;
36741916b58SGlenn Strauss return entry;
368b2991c68SGlenn Strauss }
369b2991c68SGlenn Strauss
array_insert_integer_at_pos(array * const a,const uint_fast32_t pos)37041916b58SGlenn Strauss static data_integer * array_insert_integer_at_pos(array * const a, const uint_fast32_t pos) {
371b2991c68SGlenn Strauss #if 0 /*(not currently used by lighttpd in way that reuse would occur)*/
372b2991c68SGlenn Strauss data_integer *di = (data_integer *)array_get_unused_element(a,TYPE_INTEGER);
3734f8f83eaSGlenn Strauss if (NULL == di) di = array_data_integer_init();
374b2991c68SGlenn Strauss #else
3754f8f83eaSGlenn Strauss data_integer * const di = array_data_integer_init();
376b2991c68SGlenn Strauss #endif
37741916b58SGlenn Strauss return (data_integer *)array_insert_data_at_pos(a, (data_unset *)di, pos);
378b2991c68SGlenn Strauss }
379b2991c68SGlenn Strauss
3802e0676fdSGlenn Strauss __attribute_hot__
array_insert_string_at_pos(array * const a,const uint_fast32_t pos)38141916b58SGlenn Strauss static data_string * array_insert_string_at_pos(array * const a, const uint_fast32_t pos) {
382b2991c68SGlenn Strauss data_string *ds = (data_string *)array_get_unused_element(a, TYPE_STRING);
3834f8f83eaSGlenn Strauss if (NULL == ds) ds = array_data_string_init();
38441916b58SGlenn Strauss return (data_string *)array_insert_data_at_pos(a, (data_unset *)ds, pos);
385b2991c68SGlenn Strauss }
386b2991c68SGlenn Strauss
3872e0676fdSGlenn Strauss __attribute_hot__
array_get_buf_ptr_ext(array * const a,const int ext,const char * const k,const uint32_t klen)3882e0676fdSGlenn Strauss buffer * array_get_buf_ptr_ext(array * const a, const int ext, const char * const k, const uint32_t klen) {
3892e0676fdSGlenn Strauss int32_t ipos = array_get_index_ext(a, ext, k, klen);
3902e0676fdSGlenn Strauss if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value;
3912e0676fdSGlenn Strauss
3922e0676fdSGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1));
3932e0676fdSGlenn Strauss ds->ext = ext;
3942e0676fdSGlenn Strauss buffer_copy_string_len(&ds->key, k, klen);
3952e0676fdSGlenn Strauss buffer_clear(&ds->value);
3962e0676fdSGlenn Strauss return &ds->value;
3972e0676fdSGlenn Strauss }
3982e0676fdSGlenn Strauss
array_get_int_ptr(array * const a,const char * const k,const uint32_t klen)39968ec5ad6SGlenn Strauss int * array_get_int_ptr(array * const a, const char * const k, const uint32_t klen) {
400b2991c68SGlenn Strauss int32_t ipos = array_get_index(a, k, klen);
401e3dc34d1SGlenn Strauss if (ipos >= 0) return &((data_integer *)a->sorted[ipos])->value;
402b2991c68SGlenn Strauss
403b2991c68SGlenn Strauss data_integer * const di =array_insert_integer_at_pos(a,(uint32_t)(-ipos-1));
404ad9b7e00SGlenn Strauss buffer_copy_string_len(&di->key, k, klen);
405db5ff222SGlenn Strauss di->value = 0;
406b2991c68SGlenn Strauss return &di->value;
407b2991c68SGlenn Strauss }
408b2991c68SGlenn Strauss
array_get_buf_ptr(array * const a,const char * const k,const uint32_t klen)40968ec5ad6SGlenn Strauss buffer * array_get_buf_ptr(array * const a, const char * const k, const uint32_t klen) {
410b2991c68SGlenn Strauss int32_t ipos = array_get_index(a, k, klen);
411e3dc34d1SGlenn Strauss if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value;
412b2991c68SGlenn Strauss
413b2991c68SGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1));
414ad9b7e00SGlenn Strauss buffer_copy_string_len(&ds->key, k, klen);
415601c572cSGlenn Strauss buffer_clear(&ds->value);
416601c572cSGlenn Strauss return &ds->value;
417b2991c68SGlenn Strauss }
418b2991c68SGlenn Strauss
array_insert_value(array * const a,const char * const v,const uint32_t vlen)41968ec5ad6SGlenn Strauss void array_insert_value(array * const a, const char * const v, const uint32_t vlen) {
420b2991c68SGlenn Strauss data_string * const ds = array_insert_string_at_pos(a, a->used);
421ad9b7e00SGlenn Strauss buffer_clear(&ds->key);
422601c572cSGlenn Strauss buffer_copy_string_len(&ds->value, v, vlen);
423b2991c68SGlenn Strauss }
424b2991c68SGlenn Strauss
425b2991c68SGlenn Strauss /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */
426b2991c68SGlenn Strauss __attribute_cold__
array_find_or_insert(array * const a,data_unset * const entry)427b2991c68SGlenn Strauss static data_unset **array_find_or_insert(array * const a, data_unset * const entry) {
428b2991c68SGlenn Strauss force_assert(NULL != entry);
429b2991c68SGlenn Strauss
430b2991c68SGlenn Strauss /* push value onto end of array if there is no key */
431af3df29aSGlenn Strauss if (buffer_is_unset(&entry->key)) {
432b2991c68SGlenn Strauss array_insert_data_at_pos(a, entry, a->used);
433b2991c68SGlenn Strauss return NULL;
434b2991c68SGlenn Strauss }
435b2991c68SGlenn Strauss
436b2991c68SGlenn Strauss /* try to find the entry */
437af3df29aSGlenn Strauss const int32_t ipos = array_get_index(a, BUF_PTR_LEN(&entry->key));
438e3dc34d1SGlenn Strauss if (ipos >= 0) return &a->sorted[ipos];
439b2991c68SGlenn Strauss
440b2991c68SGlenn Strauss array_insert_data_at_pos(a, entry, (uint32_t)(-ipos - 1));
4418d8ae9cbSStefan Bühler return NULL;
4428d8ae9cbSStefan Bühler }
4438d8ae9cbSStefan Bühler
4448d8ae9cbSStefan Bühler /* replace or insert data (free existing entry) */
array_replace(array * const a,data_unset * const entry)445b2991c68SGlenn Strauss void array_replace(array * const a, data_unset * const entry) {
446e3dc34d1SGlenn Strauss if (NULL == array_find_or_insert(a, entry)) return;
4478d8ae9cbSStefan Bühler
448e3dc34d1SGlenn Strauss /* find the entry (array_find_or_insert() returned non-NULL) */
449af3df29aSGlenn Strauss const int32_t ipos = array_get_index(a, BUF_PTR_LEN(&entry->key));
450e3dc34d1SGlenn Strauss force_assert(ipos >= 0);
451e3dc34d1SGlenn Strauss data_unset *old = a->sorted[ipos];
452e3dc34d1SGlenn Strauss force_assert(old != entry);
453e3dc34d1SGlenn Strauss a->sorted[ipos] = entry;
454e3dc34d1SGlenn Strauss
455e3dc34d1SGlenn Strauss uint32_t i = 0;
456e3dc34d1SGlenn Strauss while (i < a->used && a->data[i] != old) ++i;
457e3dc34d1SGlenn Strauss force_assert(i != a->used);
458e3dc34d1SGlenn Strauss a->data[i] = entry;
459e3dc34d1SGlenn Strauss
460e3dc34d1SGlenn Strauss old->fn->free(old);
4618d8ae9cbSStefan Bühler }
4628d8ae9cbSStefan Bühler
array_insert_unique(array * const a,data_unset * const entry)463b2991c68SGlenn Strauss void array_insert_unique(array * const a, data_unset * const entry) {
4648d8ae9cbSStefan Bühler data_unset **old;
4658d8ae9cbSStefan Bühler
4668d8ae9cbSStefan Bühler if (NULL != (old = array_find_or_insert(a, entry))) {
467cc8e7107SGlenn Strauss if (entry->fn->insert_dup) {
4688d8ae9cbSStefan Bühler force_assert((*old)->type == entry->type);
4698c7f1dfbSGlenn Strauss entry->fn->insert_dup(*old, entry);
4708d8ae9cbSStefan Bühler }
471cc8e7107SGlenn Strauss entry->fn->free(entry);
472cc8e7107SGlenn Strauss }
473bcdc6a3bSJan Kneschke }
474bcdc6a3bSJan Kneschke
array_is_vlist(const array * const a)475b2991c68SGlenn Strauss int array_is_vlist(const array * const a) {
476b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
477bd77abe0SGlenn Strauss data_unset *du = a->data[i];
478af3df29aSGlenn Strauss if (!buffer_is_unset(&du->key) || du->type != TYPE_STRING) return 0;
479bd77abe0SGlenn Strauss }
480bd77abe0SGlenn Strauss return 1;
481bd77abe0SGlenn Strauss }
482bd77abe0SGlenn Strauss
array_is_kvany(const array * const a)483b2991c68SGlenn Strauss int array_is_kvany(const array * const a) {
484b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
485bd77abe0SGlenn Strauss data_unset *du = a->data[i];
486af3df29aSGlenn Strauss if (buffer_is_unset(&du->key)) return 0;
487bd77abe0SGlenn Strauss }
488bd77abe0SGlenn Strauss return 1;
489bd77abe0SGlenn Strauss }
490bd77abe0SGlenn Strauss
array_is_kvarray(const array * const a)491b2991c68SGlenn Strauss int array_is_kvarray(const array * const a) {
492b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
493bd77abe0SGlenn Strauss data_unset *du = a->data[i];
494af3df29aSGlenn Strauss if (buffer_is_unset(&du->key) || du->type != TYPE_ARRAY) return 0;
495bd77abe0SGlenn Strauss }
496bd77abe0SGlenn Strauss return 1;
497bd77abe0SGlenn Strauss }
498bd77abe0SGlenn Strauss
array_is_kvstring(const array * const a)499b2991c68SGlenn Strauss int array_is_kvstring(const array * const a) {
500b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
501bd77abe0SGlenn Strauss data_unset *du = a->data[i];
502af3df29aSGlenn Strauss if (buffer_is_unset(&du->key) || du->type != TYPE_STRING) return 0;
503bd77abe0SGlenn Strauss }
504bd77abe0SGlenn Strauss return 1;
505bd77abe0SGlenn Strauss }
506bd77abe0SGlenn Strauss
507e6741acdSGlenn Strauss /* array_match_*() routines follow very similar pattern, but operate on slightly
508e6741acdSGlenn Strauss * different data: array key/value, prefix/suffix match, case-insensitive or not
509e6741acdSGlenn Strauss * While these could be combined into fewer routines with flags to modify the
510e6741acdSGlenn Strauss * behavior, the interface distinctions are useful to add clarity to the code,
511e6741acdSGlenn Strauss * and the specialized routines run slightly faster */
512e6741acdSGlenn Strauss
513e6741acdSGlenn Strauss data_unset *
array_match_key_prefix_klen(const array * const a,const char * const s,const uint32_t slen)51468ec5ad6SGlenn Strauss array_match_key_prefix_klen (const array * const a, const char * const s, const uint32_t slen)
515e6741acdSGlenn Strauss {
516b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
517ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key;
518af3df29aSGlenn Strauss const uint32_t klen = buffer_clen(key);
519e6741acdSGlenn Strauss if (klen <= slen && 0 == memcmp(s, key->ptr, klen))
520e6741acdSGlenn Strauss return a->data[i];
521e6741acdSGlenn Strauss }
522e6741acdSGlenn Strauss return NULL;
523e6741acdSGlenn Strauss }
524e6741acdSGlenn Strauss
525e6741acdSGlenn Strauss data_unset *
array_match_key_prefix_nc_klen(const array * const a,const char * const s,const uint32_t slen)52668ec5ad6SGlenn Strauss array_match_key_prefix_nc_klen (const array * const a, const char * const s, const uint32_t slen)
527e6741acdSGlenn Strauss {
528b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
529ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key;
530af3df29aSGlenn Strauss const uint32_t klen = buffer_clen(key);
531e20b5318SGlenn Strauss if (klen <= slen && buffer_eq_icase_ssn(s, key->ptr, klen))
532e6741acdSGlenn Strauss return a->data[i];
533e6741acdSGlenn Strauss }
534e6741acdSGlenn Strauss return NULL;
535e6741acdSGlenn Strauss }
536e6741acdSGlenn Strauss
537e6741acdSGlenn Strauss data_unset *
array_match_key_prefix(const array * const a,const buffer * const b)538e6741acdSGlenn Strauss array_match_key_prefix (const array * const a, const buffer * const b)
539e6741acdSGlenn Strauss {
54028f1867cSGlenn Strauss #ifdef __clang_analyzer__
54128f1867cSGlenn Strauss force_assert(b);
54228f1867cSGlenn Strauss #endif
543af3df29aSGlenn Strauss return array_match_key_prefix_klen(a, BUF_PTR_LEN(b));
544e6741acdSGlenn Strauss }
545e6741acdSGlenn Strauss
546e6741acdSGlenn Strauss data_unset *
array_match_key_prefix_nc(const array * const a,const buffer * const b)547e6741acdSGlenn Strauss array_match_key_prefix_nc (const array * const a, const buffer * const b)
548e6741acdSGlenn Strauss {
549af3df29aSGlenn Strauss return array_match_key_prefix_nc_klen(a, BUF_PTR_LEN(b));
550e6741acdSGlenn Strauss }
551e6741acdSGlenn Strauss
552e6741acdSGlenn Strauss const buffer *
array_match_value_prefix(const array * const a,const buffer * const b)553e6741acdSGlenn Strauss array_match_value_prefix (const array * const a, const buffer * const b)
554e6741acdSGlenn Strauss {
555af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
556e6741acdSGlenn Strauss
557b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
558601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value;
559af3df29aSGlenn Strauss const uint32_t vlen = buffer_clen(value);
560e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen))
561e6741acdSGlenn Strauss return value;
562e6741acdSGlenn Strauss }
563e6741acdSGlenn Strauss return NULL;
564e6741acdSGlenn Strauss }
565e6741acdSGlenn Strauss
566e6741acdSGlenn Strauss const buffer *
array_match_value_prefix_nc(const array * const a,const buffer * const b)567e6741acdSGlenn Strauss array_match_value_prefix_nc (const array * const a, const buffer * const b)
568e6741acdSGlenn Strauss {
569af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
570e6741acdSGlenn Strauss
571b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
572601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value;
573af3df29aSGlenn Strauss const uint32_t vlen = buffer_clen(value);
574e20b5318SGlenn Strauss if (vlen <= blen && buffer_eq_icase_ssn(b->ptr, value->ptr, vlen))
575e6741acdSGlenn Strauss return value;
576e6741acdSGlenn Strauss }
577e6741acdSGlenn Strauss return NULL;
578e6741acdSGlenn Strauss }
579e6741acdSGlenn Strauss
580e6741acdSGlenn Strauss data_unset *
array_match_key_suffix(const array * const a,const buffer * const b)581e6741acdSGlenn Strauss array_match_key_suffix (const array * const a, const buffer * const b)
582e6741acdSGlenn Strauss {
583af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
584e6741acdSGlenn Strauss const char * const end = b->ptr + blen;
585e6741acdSGlenn Strauss
586b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
587ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key;
588af3df29aSGlenn Strauss const uint32_t klen = buffer_clen(key);
589e6741acdSGlenn Strauss if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen))
590e6741acdSGlenn Strauss return a->data[i];
591e6741acdSGlenn Strauss }
592e6741acdSGlenn Strauss return NULL;
593e6741acdSGlenn Strauss }
594e6741acdSGlenn Strauss
595e6741acdSGlenn Strauss data_unset *
array_match_key_suffix_nc(const array * const a,const buffer * const b)596e6741acdSGlenn Strauss array_match_key_suffix_nc (const array * const a, const buffer * const b)
597e6741acdSGlenn Strauss {
598af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
599e6741acdSGlenn Strauss const char * const end = b->ptr + blen;
600e6741acdSGlenn Strauss
601b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
602ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key;
603af3df29aSGlenn Strauss const uint32_t klen = buffer_clen(key);
604e20b5318SGlenn Strauss if (klen <= blen && buffer_eq_icase_ssn(end - klen, key->ptr, klen))
605e6741acdSGlenn Strauss return a->data[i];
606e6741acdSGlenn Strauss }
607e6741acdSGlenn Strauss return NULL;
608e6741acdSGlenn Strauss }
609e6741acdSGlenn Strauss
610e6741acdSGlenn Strauss const buffer *
array_match_value_suffix(const array * const a,const buffer * const b)611e6741acdSGlenn Strauss array_match_value_suffix (const array * const a, const buffer * const b)
612e6741acdSGlenn Strauss {
613af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
614e6741acdSGlenn Strauss const char * const end = b->ptr + blen;
615e6741acdSGlenn Strauss
616b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
617601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value;
618af3df29aSGlenn Strauss const uint32_t vlen = buffer_clen(value);
619e6741acdSGlenn Strauss if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen))
620e6741acdSGlenn Strauss return value;
621e6741acdSGlenn Strauss }
622e6741acdSGlenn Strauss return NULL;
623e6741acdSGlenn Strauss }
624e6741acdSGlenn Strauss
625e6741acdSGlenn Strauss const buffer *
array_match_value_suffix_nc(const array * const a,const buffer * const b)626e6741acdSGlenn Strauss array_match_value_suffix_nc (const array * const a, const buffer * const b)
627e6741acdSGlenn Strauss {
628af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
629e6741acdSGlenn Strauss const char * const end = b->ptr + blen;
630e6741acdSGlenn Strauss
631b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
632601c572cSGlenn Strauss const buffer * const value = &((data_string *)a->data[i])->value;
633af3df29aSGlenn Strauss const uint32_t vlen = buffer_clen(value);
634e20b5318SGlenn Strauss if (vlen <= blen && buffer_eq_icase_ssn(end - vlen, value->ptr, vlen))
635e6741acdSGlenn Strauss return value;
636e6741acdSGlenn Strauss }
637e6741acdSGlenn Strauss return NULL;
638e6741acdSGlenn Strauss }
639e6741acdSGlenn Strauss
640e6741acdSGlenn Strauss data_unset *
array_match_path_or_ext(const array * const a,const buffer * const b)641e6741acdSGlenn Strauss array_match_path_or_ext (const array * const a, const buffer * const b)
642e6741acdSGlenn Strauss {
643af3df29aSGlenn Strauss const uint32_t blen = buffer_clen(b);
644e6741acdSGlenn Strauss
645b2991c68SGlenn Strauss for (uint32_t i = 0; i < a->used; ++i) {
646e6741acdSGlenn Strauss /* check extension in the form "^/path" or ".ext$" */
647ad9b7e00SGlenn Strauss const buffer * const key = &a->data[i]->key;
648af3df29aSGlenn Strauss const uint32_t klen = buffer_clen(key);
649e6741acdSGlenn Strauss if (klen <= blen
650e6741acdSGlenn Strauss && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen),
651e6741acdSGlenn Strauss key->ptr, klen))
652e6741acdSGlenn Strauss return a->data[i];
653e6741acdSGlenn Strauss }
654e6741acdSGlenn Strauss return NULL;
655e6741acdSGlenn Strauss }
656