diff options
author | Graham Leggett <minfrin@apache.org> | 2013-05-07 20:52:42 +0000 |
---|---|---|
committer | Graham Leggett <minfrin@apache.org> | 2013-05-07 20:52:42 +0000 |
commit | ebf945ef07b94e229909fa991013efa7d1ad3b99 (patch) | |
tree | c028cbae193437f31e4251dec64a582a722218f6 /tables | |
parent | 64a947821ca5e3cdd7f6ae16fc7eb7c1bef3b362 (diff) | |
download | apr-ebf945ef07b94e229909fa991013efa7d1ad3b99.tar.gz |
Backport r1480067 to v1.5 branch.
Add the apr_table_getm() call, which transparently handles the
merging of keys with multiple values.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.5.x@1480071 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'tables')
-rw-r--r-- | tables/apr_tables.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/tables/apr_tables.c b/tables/apr_tables.c index 7479ef47c..7c82583e3 100644 --- a/tables/apr_tables.c +++ b/tables/apr_tables.c @@ -357,6 +357,14 @@ struct apr_table_t { int index_last[TABLE_HASH_SIZE]; }; +/* keep state for apr_table_getm() */ +typedef struct +{ + apr_pool_t *p; + const char *first; + apr_array_header_t *merged; +} table_getm_t; + /* * NOTICE: if you tweak this you should look at is_empty_table() * and table_elts() in alloc.h @@ -1236,3 +1244,51 @@ APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b, apr_table_compress(a, flags); } + +static int table_getm_do(void *v, const char *key, const char *val) +{ + table_getm_t *state = (table_getm_t *) v; + + if (!state->first) { + /** + * The most common case is a single header, and this is covered by + * a fast path that doesn't allocate any memory. On the second and + * subsequent header, an array is created and the array concatenated + * together to form the final value. + */ + state->first = val; + } + else { + const char **elt; + if (!state->merged) { + state->merged = apr_array_make(state->p, 10, sizeof(const char *)); + elt = apr_array_push(state->merged); + *elt = state->first; + } + elt = apr_array_push(state->merged); + *elt = val; + } + return 1; +} + +APR_DECLARE(const char *) apr_table_getm(apr_pool_t *p, const apr_table_t *t, + const char *key) +{ + table_getm_t state; + + state.p = p; + state.first = NULL; + state.merged = NULL; + + apr_table_do(table_getm_do, &state, t, key, NULL); + + if (!state.first) { + return NULL; + } + else if (!state.merged) { + return state.first; + } + else { + return apr_array_pstrcat(p, state.merged, ','); + } +} |