From 68e4a416cc9936a1d5d168f199ac88a8e24b75e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Tue, 15 Mar 2016 18:56:02 +0000 Subject: [PATCH] [core] provide array_extract_element and use it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Stefan Bühler git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@3102 152afb58-edef-0310-8abb-c4023f1b3aa9 --- NEWS | 1 + src/array.c | 39 +++++++++++++++++++++++++++++++++++++++ src/array.h | 1 + src/configparser.y | 22 +--------------------- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/NEWS b/NEWS index 7aa27219..23c7bba8 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,7 @@ NEWS * [core] improve array API to prevent memory leaks * [core] refactor array search; raise array size limit to SSIZE_MAX * [core] fix memory leak in configparser_merge_data + * [core] provide array_extract_element and use it - 1.4.39 - 2016-01-02 * [core] fix memset_s call (fixes #2698) diff --git a/src/array.c b/src/array.c index 105aeedf..05b03702 100644 --- a/src/array.c +++ b/src/array.c @@ -134,6 +134,45 @@ data_unset *array_get_element(array *a, const char *key) { return NULL; } +data_unset *array_extract_element(array *a, const char *key) { + size_t ndx, pos; + force_assert(NULL != key); + + if (ARRAY_NOT_FOUND != (ndx = array_get_index(a, key, strlen(key), &pos))) { + /* found */ + const size_t last_ndx = a->used - 1; + data_unset *entry = a->data[ndx]; + + /* now we need to swap it with the last element (if it isn't already the last element) */ + if (ndx != last_ndx) { + /* to swap we also need to modify the index in a->sorted - find pos of last_elem there */ + size_t last_elem_pos; + /* last element must be present at the expected position */ + force_assert(last_ndx == array_get_index(a, CONST_BUF_LEN(a->data[last_ndx]->key), &last_elem_pos)); + + /* move entry from last_ndx to ndx */ + a->data[ndx] = a->data[last_ndx]; + a->data[last_ndx] = NULL; + + /* fix index entry for moved entry */ + a->sorted[last_elem_pos] = ndx; + } else { + a->data[ndx] = NULL; + } + + /* remove entry in a->sorted: move everything after pos one step to the left */ + if (pos != last_ndx) { + memmove(a->sorted + pos, a->sorted + pos + 1, (last_ndx - pos) * sizeof(*a->sorted)); + } + a->sorted[last_ndx] = ARRAY_NOT_FOUND; + --a->used; + + return entry; + } + + return NULL; +} + data_unset *array_get_unused_element(array *a, data_type_t t) { data_unset *ds = NULL; unsigned int i; diff --git a/src/array.h b/src/array.h index 9d6085b3..964f2316 100644 --- a/src/array.h +++ b/src/array.h @@ -166,6 +166,7 @@ data_unset *array_pop(array *a); /* only works on "simple" lists with autogenera int array_print(array *a, int depth); data_unset *array_get_unused_element(array *a, data_type_t t); data_unset *array_get_element(array *a, const char *key); +data_unset *array_extract_element(array *a, const char *key); /* removes found entry from array */ void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len); void array_replace(array *a, data_unset *entry); int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len); diff --git a/src/configparser.y b/src/configparser.y index 24efb6b0..ab69633b 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -177,27 +177,7 @@ varline ::= key(A) APPEND expression(B). { ctx->current->context_ndx, ctx->current->key->ptr, A->ptr); ctx->ok = 0; - } else if (NULL != (du = array_get_element(vars, A->ptr))) { - /* exists in current block */ - if (du->type != B->type) { - /* might create new data when merging different types; need to replace old array entry */ - /* also merging will kill the old data */ - du = du->copy(du); - du = configparser_merge_data(du, B); - if (NULL != du) { - buffer_copy_buffer(du->key, A); - array_replace(vars, du); - } - } else { - data_unset *old_du = du; - du = configparser_merge_data(old_du, B); - force_assert((NULL == du) || (du == old_du)); /* must not create new data when types match */ - } - if (NULL == du) { - ctx->ok = 0; - } - B->free(B); - } else if (NULL != (du = configparser_get_variable(ctx, A))) { + } else if (NULL != (du = array_extract_element(vars, A->ptr)) || NULL != (du = configparser_get_variable(ctx, A))) { du = configparser_merge_data(du, B); if (NULL == du) { ctx->ok = 0;