summaryrefslogtreecommitdiff
path: root/tables
diff options
context:
space:
mode:
authorGraham Leggett <minfrin@apache.org>2013-05-07 20:52:42 +0000
committerGraham Leggett <minfrin@apache.org>2013-05-07 20:52:42 +0000
commitebf945ef07b94e229909fa991013efa7d1ad3b99 (patch)
treec028cbae193437f31e4251dec64a582a722218f6 /tables
parent64a947821ca5e3cdd7f6ae16fc7eb7c1bef3b362 (diff)
downloadapr-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.c56
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, ',');
+ }
+}