xref: /lighttpd1.4/src/array.c (revision 2c409321)
1 #include "first.h"
2 
3 #include "array.h"
4 #include "buffer.h"
5 
6 #include <string.h>
7 #include <stdlib.h>
8 #include <limits.h>
9 
10 #include <errno.h>
11 #include <assert.h>
12 
13 #define ARRAY_NOT_FOUND ((size_t)(-1))
14 
15 array *array_init(void) {
16 	array *a;
17 
18 	a = calloc(1, sizeof(*a));
19 	force_assert(a);
20 
21 	return a;
22 }
23 
24 array *array_init_array(array *src) {
25 	size_t i;
26 	array *a = array_init();
27 
28 	if (0 == src->size) return a;
29 
30 	a->used = src->used;
31 	a->size = src->size;
32 	a->unique_ndx = src->unique_ndx;
33 
34 	a->data = malloc(sizeof(*src->data) * src->size);
35 	force_assert(NULL != a->data);
36 	for (i = 0; i < src->size; i++) {
37 		if (src->data[i]) a->data[i] = src->data[i]->fn->copy(src->data[i]);
38 		else a->data[i] = NULL;
39 	}
40 
41 	a->sorted = malloc(sizeof(*src->sorted) * src->size);
42 	force_assert(NULL != a->sorted);
43 	memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size);
44 	return a;
45 }
46 
47 void array_free(array *a) {
48 	size_t i;
49 	if (!a) return;
50 
51 	for (i = 0; i < a->size; i++) {
52 		if (a->data[i]) a->data[i]->fn->free(a->data[i]);
53 	}
54 
55 	if (a->data) free(a->data);
56 	if (a->sorted) free(a->sorted);
57 
58 	free(a);
59 }
60 
61 void array_reset(array *a) {
62 	size_t i;
63 	if (!a) return;
64 
65 	for (i = 0; i < a->used; i++) {
66 		a->data[i]->fn->reset(a->data[i]);
67 		a->data[i]->is_index_key = 0;
68 	}
69 
70 	a->used = 0;
71 	a->unique_ndx = 0;
72 }
73 
74 void array_reset_data_strings(array *a) {
75 	if (!a) return;
76 
77 	for (size_t i = 0; i < a->used; ++i) {
78 		data_string * const ds = (data_string *)a->data[i];
79 		/*force_assert(ds->type == TYPE_STRING);*/
80 		ds->is_index_key = 0;
81 		buffer_reset(ds->key);
82 		buffer_reset(ds->value);
83 	}
84 
85 	a->used = 0;
86 	a->unique_ndx = 0;
87 }
88 
89 data_unset *array_pop(array *a) {
90 	data_unset *du;
91 
92 	force_assert(a->used != 0);
93 
94 	a->used --;
95 	du = a->data[a->used];
96 	force_assert(a->sorted[a->used] == a->used); /* only works on "simple" lists */
97 	a->data[a->used] = NULL;
98 
99 	return du;
100 }
101 
102 __attribute_pure__
103 static int array_caseless_compare(const char * const a, const char * const b, const size_t len) {
104     for (size_t i = 0; i < len; ++i) {
105         unsigned int ca = ((unsigned char *)a)[i];
106         unsigned int cb = ((unsigned char *)b)[i];
107         if (ca == cb) continue;
108 
109         /* always lowercase for transitive results */
110         if (ca >= 'A' && ca <= 'Z') ca |= 32;
111         if (cb >= 'A' && cb <= 'Z') cb |= 32;
112 
113         if (ca == cb) continue;
114         return (int)(ca - cb);
115     }
116     return 0;
117 }
118 
119 __attribute_pure__
120 static int array_keycmp(const char *a, size_t alen, const char *b, size_t blen) {
121     return alen < blen ? -1 : alen > blen ? 1 : array_caseless_compare(a, b, blen);
122 }
123 
124 /* returns index of element or ARRAY_NOT_FOUND
125  * if rndx != NULL it stores the position in a->sorted[] where the key needs
126  * to be inserted
127  */
128 static size_t array_get_index(const array *a, const char *key, size_t keylen, size_t *rndx) {
129 	/* invariant: [lower-1] < key < [upper]
130 	 * "virtual elements": [-1] = -INFTY, [a->used] = +INFTY
131 	 * also an invariant: 0 <= lower <= upper <= a->used
132 	 */
133 	size_t lower = 0, upper = a->used;
134 	force_assert(upper <= SSIZE_MAX); /* (lower + upper) can't overflow */
135 
136 	while (lower != upper) {
137 		size_t probe = (lower + upper) / 2;
138 		const buffer *b = a->data[a->sorted[probe]]->key;
139 		int cmp = array_keycmp(key, keylen, CONST_BUF_LEN(b));
140 
141 		if (cmp == 0) {
142 			/* found */
143 			if (rndx) *rndx = probe;
144 			return a->sorted[probe];
145 		} else if (cmp < 0) {
146 			/* key < [probe] */
147 			upper = probe; /* still: lower <= upper */
148 		} else {
149 			/* key > [probe] */
150 			lower = probe + 1; /* still: lower <= upper */
151 		}
152 	}
153 
154 	/* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */
155 	if (rndx) *rndx = lower;
156 	return ARRAY_NOT_FOUND;
157 }
158 
159 data_unset *array_get_element_klen(const array *a, const char *key, size_t klen) {
160 	size_t ndx;
161 	force_assert(NULL != key);
162 
163 	if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, NULL))) {
164 		/* found, return it */
165 		return a->data[ndx];
166 	}
167 
168 	return NULL;
169 }
170 
171 data_unset *array_extract_element_klen(array *a, const char *key, size_t klen) {
172 	size_t ndx, pos;
173 	force_assert(NULL != key);
174 
175 	if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, klen, &pos))) {
176 		/* found */
177 		const size_t last_ndx = a->used - 1;
178 		data_unset *entry = a->data[ndx];
179 
180 		/* now we need to swap it with the last element (if it isn't already the last element) */
181 		if (ndx != last_ndx) {
182 			/* to swap we also need to modify the index in a->sorted - find pos of last_elem there */
183 			size_t last_elem_pos;
184 			/* last element must be present at the expected position */
185 			force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos));
186 
187 			/* move entry from last_ndx to ndx */
188 			a->data[ndx] = a->data[last_ndx];
189 			a->data[last_ndx] = NULL;
190 
191 			/* fix index entry for moved entry */
192 			a->sorted[last_elem_pos] = ndx;
193 		} else {
194 			a->data[ndx] = NULL;
195 		}
196 
197 		/* remove entry in a->sorted: move everything after pos one step to the left */
198 		if (pos != last_ndx) {
199 			memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted));
200 		}
201 		a->sorted[last_ndx] = ARRAY_NOT_FOUND;
202 		--a->used;
203 
204 		return entry;
205 	}
206 
207 	return NULL;
208 }
209 
210 static data_unset *array_get_unused_element(array *a, data_type_t t) {
211 	data_unset *ds = NULL;
212 	unsigned int i;
213 
214 	for (i = a->used; i < a->size; i++) {
215 		if (a->data[i] && a->data[i]->type == t) {
216 			ds = a->data[i];
217 
218 			/* make empty slot at a->used for next insert */
219 			a->data[i] = a->data[a->used];
220 			a->data[a->used] = NULL;
221 
222 			return ds;
223 		}
224 	}
225 
226 	return NULL;
227 }
228 
229 void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
230 	data_string *ds;
231 
232 	if (NULL != (ds = (data_string *)array_get_element_klen(hdrs, key, key_len))) {
233 		buffer_copy_string_len(ds->value, value, val_len);
234 		return;
235 	}
236 
237 	array_insert_key_value(hdrs, key, key_len, value, val_len);
238 }
239 
240 void array_insert_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
241 	data_string *ds;
242 
243 	if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
244 		ds = data_string_init();
245 	}
246 
247 	buffer_copy_string_len(ds->key, key, key_len);
248 	buffer_copy_string_len(ds->value, value, val_len);
249 	array_insert_unique(hdrs, (data_unset *)ds);
250 }
251 
252 void array_insert_value(array *hdrs, const char *value, size_t val_len) {
253 	data_string *ds;
254 
255 	if (NULL == (ds = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
256 		ds = data_string_init();
257 	}
258 
259 	buffer_copy_string_len(ds->value, value, val_len);
260 	array_insert_unique(hdrs, (data_unset *)ds);
261 }
262 
263 int * array_get_int_ptr(array *a, const char *k, size_t klen) {
264 	data_integer *di = (data_integer *)array_get_element_klen(a, k, klen);
265 
266 	if (NULL == di) {
267 		di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER);
268 		if (NULL == di) di = data_integer_init();
269 		buffer_copy_string_len(di->key, k, klen);
270 		array_insert_unique(a, (data_unset *)di);
271 	}
272 
273 	return &di->value;
274 }
275 
276 /* if entry already exists return pointer to existing entry, otherwise insert entry and return NULL */
277 static data_unset **array_find_or_insert(array *a, data_unset *entry) {
278 	size_t ndx, pos, j;
279 
280 	/* generate unique index if neccesary */
281 	if (buffer_is_empty(entry->key) || entry->is_index_key) {
282 		buffer_copy_int(entry->key, a->unique_ndx++);
283 		entry->is_index_key = 1;
284 		force_assert(0 != a->unique_ndx); /* must not wrap or we'll get problems */
285 	}
286 
287 	/* try to find the entry */
288 	if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, CONST_BUF_LEN(entry->key), &pos))) {
289 		/* found collision, return it */
290 		return &a->data[ndx];
291 	}
292 
293 	/* insert */
294 
295 	/* there couldn't possibly be enough memory to store so many entries */
296 	force_assert(a->used + 1 <= SSIZE_MAX);
297 
298 	if (a->size == a->used) {
299 		a->size  += 16;
300 		a->data   = realloc(a->data,   sizeof(*a->data)   * a->size);
301 		a->sorted = realloc(a->sorted, sizeof(*a->sorted) * a->size);
302 		force_assert(a->data);
303 		force_assert(a->sorted);
304 		for (j = a->used; j < a->size; j++) a->data[j] = NULL;
305 	}
306 
307 	ndx = a->used;
308 
309 	/* make sure there is nothing here */
310 	if (a->data[ndx]) a->data[ndx]->fn->free(a->data[ndx]);
311 
312 	a->data[a->used++] = entry;
313 
314 	/* move everything one step to the right */
315 	if (pos != ndx) {
316 		memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
317 	}
318 
319 	/* insert */
320 	a->sorted[pos] = ndx;
321 
322 	return NULL;
323 }
324 
325 /* replace or insert data (free existing entry) */
326 void array_replace(array *a, data_unset *entry) {
327 	data_unset **old;
328 
329 	force_assert(NULL != entry);
330 	if (NULL != (old = array_find_or_insert(a, entry))) {
331 		force_assert(*old != entry);
332 		(*old)->fn->free(*old);
333 		*old = entry;
334 	}
335 }
336 
337 void array_insert_unique(array *a, data_unset *entry) {
338 	data_unset **old;
339 
340 	force_assert(NULL != entry);
341 	if (NULL != (old = array_find_or_insert(a, entry))) {
342 		force_assert((*old)->type == entry->type);
343 		entry->fn->insert_dup(*old, entry);
344 	}
345 }
346 
347 int array_is_vlist(array *a) {
348 	for (size_t i = 0; i < a->used; ++i) {
349 		data_unset *du = a->data[i];
350 		if (!du->is_index_key || du->type != TYPE_STRING) return 0;
351 	}
352 	return 1;
353 }
354 
355 int array_is_kvany(array *a) {
356 	for (size_t i = 0; i < a->used; ++i) {
357 		data_unset *du = a->data[i];
358 		if (du->is_index_key) return 0;
359 	}
360 	return 1;
361 }
362 
363 int array_is_kvarray(array *a) {
364 	for (size_t i = 0; i < a->used; ++i) {
365 		data_unset *du = a->data[i];
366 		if (du->is_index_key || du->type != TYPE_ARRAY) return 0;
367 	}
368 	return 1;
369 }
370 
371 int array_is_kvstring(array *a) {
372 	for (size_t i = 0; i < a->used; ++i) {
373 		data_unset *du = a->data[i];
374 		if (du->is_index_key || du->type != TYPE_STRING) return 0;
375 	}
376 	return 1;
377 }
378 
379 /* array_match_*() routines follow very similar pattern, but operate on slightly
380  * different data: array key/value, prefix/suffix match, case-insensitive or not
381  * While these could be combined into fewer routines with flags to modify the
382  * behavior, the interface distinctions are useful to add clarity to the code,
383  * and the specialized routines run slightly faster */
384 
385 data_unset *
386 array_match_key_prefix_klen (const array * const a, const char * const s, const size_t slen)
387 {
388     for (size_t i = 0; i < a->used; ++i) {
389         const buffer * const key = a->data[i]->key;
390         const size_t klen = buffer_string_length(key);
391         if (klen <= slen && 0 == memcmp(s, key->ptr, klen))
392             return a->data[i];
393     }
394     return NULL;
395 }
396 
397 data_unset *
398 array_match_key_prefix_nc_klen (const array * const a, const char * const s, const size_t slen)
399 {
400     for (size_t i = 0; i < a->used; ++i) {
401         const buffer * const key = a->data[i]->key;
402         const size_t klen = buffer_string_length(key);
403         if (klen <= slen && buffer_eq_icase_ssn(s, key->ptr, klen))
404             return a->data[i];
405     }
406     return NULL;
407 }
408 
409 data_unset *
410 array_match_key_prefix (const array * const a, const buffer * const b)
411 {
412     return array_match_key_prefix_klen(a, CONST_BUF_LEN(b));
413 }
414 
415 data_unset *
416 array_match_key_prefix_nc (const array * const a, const buffer * const b)
417 {
418     return array_match_key_prefix_nc_klen(a, CONST_BUF_LEN(b));
419 }
420 
421 const buffer *
422 array_match_value_prefix (const array * const a, const buffer * const b)
423 {
424     const size_t blen = buffer_string_length(b);
425 
426     for (size_t i = 0; i < a->used; ++i) {
427         const buffer * const value = ((data_string *)a->data[i])->value;
428         const size_t vlen = buffer_string_length(value);
429         if (vlen <= blen && 0 == memcmp(b->ptr, value->ptr, vlen))
430             return value;
431     }
432     return NULL;
433 }
434 
435 const buffer *
436 array_match_value_prefix_nc (const array * const a, const buffer * const b)
437 {
438     const size_t blen = buffer_string_length(b);
439 
440     for (size_t i = 0; i < a->used; ++i) {
441         const buffer * const value = ((data_string *)a->data[i])->value;
442         const size_t vlen = buffer_string_length(value);
443         if (vlen <= blen && buffer_eq_icase_ssn(b->ptr, value->ptr, vlen))
444             return value;
445     }
446     return NULL;
447 }
448 
449 data_unset *
450 array_match_key_suffix (const array * const a, const buffer * const b)
451 {
452     const size_t blen = buffer_string_length(b);
453     const char * const end = b->ptr + blen;
454 
455     for (size_t i = 0; i < a->used; ++i) {
456         const buffer * const key = a->data[i]->key;
457         const size_t klen = buffer_string_length(key);
458         if (klen <= blen && 0 == memcmp(end - klen, key->ptr, klen))
459             return a->data[i];
460     }
461     return NULL;
462 }
463 
464 data_unset *
465 array_match_key_suffix_nc (const array * const a, const buffer * const b)
466 {
467     const size_t blen = buffer_string_length(b);
468     const char * const end = b->ptr + blen;
469 
470     for (size_t i = 0; i < a->used; ++i) {
471         const buffer * const key = a->data[i]->key;
472         const size_t klen = buffer_string_length(key);
473         if (klen <= blen && buffer_eq_icase_ssn(end - klen, key->ptr, klen))
474             return a->data[i];
475     }
476     return NULL;
477 }
478 
479 const buffer *
480 array_match_value_suffix (const array * const a, const buffer * const b)
481 {
482     const size_t blen = buffer_string_length(b);
483     const char * const end = b->ptr + blen;
484 
485     for (size_t i = 0; i < a->used; ++i) {
486         const buffer * const value = ((data_string *)a->data[i])->value;
487         const size_t vlen = buffer_string_length(value);
488         if (vlen <= blen && 0 == memcmp(end - vlen, value->ptr, vlen))
489             return value;
490     }
491     return NULL;
492 }
493 
494 const buffer *
495 array_match_value_suffix_nc (const array * const a, const buffer * const b)
496 {
497     const size_t blen = buffer_string_length(b);
498     const char * const end = b->ptr + blen;
499 
500     for (size_t i = 0; i < a->used; ++i) {
501         const buffer * const value = ((data_string *)a->data[i])->value;
502         const size_t vlen = buffer_string_length(value);
503         if (vlen <= blen && buffer_eq_icase_ssn(end - vlen, value->ptr, vlen))
504             return value;
505     }
506     return NULL;
507 }
508 
509 data_unset *
510 array_match_path_or_ext (const array * const a, const buffer * const b)
511 {
512     const size_t blen = buffer_string_length(b);
513 
514     for (size_t i = 0; i < a->used; ++i) {
515         /* check extension in the form "^/path" or ".ext$" */
516         const buffer * const key = a->data[i]->key;
517         const size_t klen = buffer_string_length(key);
518         if (klen <= blen
519             && 0 == memcmp((*(key->ptr) == '/' ? b->ptr : b->ptr + blen - klen),
520                            key->ptr, klen))
521             return a->data[i];
522     }
523     return NULL;
524 }
525 
526 
527 
528 
529 
530 #include <stdio.h>
531 
532 void array_print_indent(int depth) {
533 	int i;
534 	for (i = 0; i < depth; i ++) {
535 		fprintf(stdout, "    ");
536 	}
537 }
538 
539 size_t array_get_max_key_length(array *a) {
540 	size_t maxlen, i;
541 
542 	maxlen = 0;
543 	for (i = 0; i < a->used; i ++) {
544 		data_unset *du = a->data[i];
545 		size_t len = buffer_string_length(du->key);
546 
547 		if (len > maxlen) {
548 			maxlen = len;
549 		}
550 	}
551 	return maxlen;
552 }
553 
554 int array_print(array *a, int depth) {
555 	size_t i;
556 	size_t maxlen;
557 	int oneline = 1;
558 
559 	if (a->used > 5) {
560 		oneline = 0;
561 	}
562 	for (i = 0; i < a->used && oneline; i++) {
563 		data_unset *du = a->data[i];
564 		if (!du->is_index_key) {
565 			oneline = 0;
566 			break;
567 		}
568 		switch (du->type) {
569 			case TYPE_INTEGER:
570 			case TYPE_STRING:
571 				break;
572 			default:
573 				oneline = 0;
574 				break;
575 		}
576 	}
577 	if (oneline) {
578 		fprintf(stdout, "(");
579 		for (i = 0; i < a->used; i++) {
580 			data_unset *du = a->data[i];
581 			if (i != 0) {
582 				fprintf(stdout, ", ");
583 			}
584 			du->fn->print(du, depth + 1);
585 		}
586 		fprintf(stdout, ")");
587 		return 0;
588 	}
589 
590 	maxlen = array_get_max_key_length(a);
591 	fprintf(stdout, "(\n");
592 	for (i = 0; i < a->used; i++) {
593 		data_unset *du = a->data[i];
594 		array_print_indent(depth + 1);
595 		if (!du->is_index_key) {
596 			int j;
597 
598 			if (i && (i % 5) == 0) {
599 				fprintf(stdout, "# %zu\n", i);
600 				array_print_indent(depth + 1);
601 			}
602 			fprintf(stdout, "\"%s\"", du->key->ptr);
603 			for (j = maxlen - buffer_string_length(du->key); j > 0; j--) {
604 				fprintf(stdout, " ");
605 			}
606 			fprintf(stdout, " => ");
607 		}
608 		du->fn->print(du, depth + 1);
609 		fprintf(stdout, ",\n");
610 	}
611 	if (!(i && (i - 1 % 5) == 0)) {
612 		array_print_indent(depth + 1);
613 		fprintf(stdout, "# %zu\n", i);
614 	}
615 	array_print_indent(depth);
616 	fprintf(stdout, ")");
617 
618 	return 0;
619 }
620