You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@locus.apache.org on 2000/08/22 23:55:36 UTC
cvs commit: apache-2.0/src/lib/apr/tables apr_tables.c
coar 00/08/22 14:55:35
Modified: src CHANGES
src/lib/apr/include apr_tables.h
src/lib/apr/tables apr_tables.c
Log:
Add UNTESTED routines and structures to APR's table implementation
to allow for tables with string keys and non-string values.
Instead of a char * value field, these tables have an apr_item_t *
value field, which in turn is a structure containing a size and
a void * pointer to the data themselves. I've kept the types
distinct to keep type-checking useful, so they can't be accidentally
intermixed in function calls.
I've used 'btable' in place of 'table' in all cases, so the
structures are apr_btable_t and apr_btable_entry_t. I've
prototyped and cloned all of the relevant routines except
apr_table_to() and apr_overlap_tables(), which were both too
complex for me to want to tackle to-night. Some of the routines
don't make sense to clone, like apr_table_merge*().
So maybe this all sucks and someone can rip it out, but I'm
sick of waiting for this functionality so I hope someone
takes this and improves it instead.
We *could* reimplement the string-value tables as a special
case of btables, which would conceivably save on strlen() cycles,
but I'm not sure it would be worth it.
Revision Changes Path
1.211 +3 -0 apache-2.0/src/CHANGES
Index: CHANGES
===================================================================
RCS file: /home/cvs/apache-2.0/src/CHANGES,v
retrieving revision 1.210
retrieving revision 1.211
diff -u -u -r1.210 -r1.211
--- CHANGES 2000/08/21 19:08:59 1.210
+++ CHANGES 2000/08/22 21:55:33 1.211
@@ -1,5 +1,8 @@
Changes with Apache 2.0a7
+ *) Add tables with non-string/binary values to APR.
+ [Ken Coar]
+
*) Fix some bad calls to ap_log_rerror() in mod_rewrite.
[Jeff Trawick]
1.7 +101 -28 apache-2.0/src/lib/apr/include/apr_tables.h
Index: apr_tables.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_tables.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -u -r1.6 -r1.7
--- apr_tables.h 2000/08/06 06:07:09 1.6
+++ apr_tables.h 2000/08/22 21:55:34 1.7
@@ -84,6 +84,7 @@
* published.
*/
typedef struct apr_table_t apr_table_t;
+typedef struct apr_btable_t apr_btable_t;
typedef struct apr_array_header_t apr_array_header_t;
/** An opaque array type */
@@ -100,7 +101,7 @@
char *elts;
};
-/** The opaque table type */
+/** The opaque string-content table type */
struct apr_table_t {
/* This has to be first to promote backwards compatibility with
* older modules which cast a apr_table_t * to an apr_array_header_t *...
@@ -115,9 +116,27 @@
#endif
};
+/** The opaque binary-content table type */
+struct apr_btable_t {
+ /* This has to be first to promote backwards compatibility with
+ * older modules which cast a apr_table_t * to an apr_array_header_t *...
+ * they should use the table_elts() function for most of the
+ * cases they do this for.
+ */
+ /** The underlying array for the table */
+ apr_array_header_t a;
+#ifdef MAKE_TABLE_PROFILE
+ /** Who created the array. */
+ void *creator;
+#endif
+};
+
+/**
+ * The (opaque) structure for string-content tables.
+ */
typedef struct apr_table_entry_t apr_table_entry_t;
-/** The type for each entry in a table */
+/** The type for each entry in a string-content table */
struct apr_table_entry_t {
/** The key for the current table entry */
char *key; /* maybe NULL in future;
@@ -127,16 +146,51 @@
char *val;
};
+/**
+ * The (opaque) structure for binary-content tables.
+ */
+typedef struct apr_btable_entry_t apr_btable_entry_t;
+
+/**
+ * A transparent type for items stored in binary-content tables, and
+ * possibly elsewhere.
+ */
+typedef struct apr_item_t {
+ /** The key for the current table entry */
+ char *key; /* maybe NULL in future;
+ * check when iterating thru table_elts
+ */
+ /** Size of the opaque block comprising the item's content. */
+ size_t size;
+ /** A pointer to the content itself. */
+ void *data;
+} apr_item_t;
+
+/** The type for each entry in a binary-content table */
+struct apr_btable_entry_t {
+ /** The key for the current table entry */
+ char *key; /* maybe NULL in future;
+ * check when iterating thru table_elts
+ */
+ /** The value for the current table entry */
+ apr_item_t *val;
+};
+
/* XXX: these know about the definition of struct apr_table_t in alloc.c. That
* definition is not here because it is supposed to be private, and by not
* placing it here we are able to get compile-time diagnostics from modules
- * written which assume that a apr_table_t is the same as an apr_array_header_t. -djg
+ * written which assume that a apr_table_t is the same as an
+ * apr_array_header_t. -djg
*/
#define apr_table_elts(t) ((apr_array_header_t *)(t))
-#define apr_is_empty_table(t) (((t) == NULL)||(((apr_array_header_t *)(t))->nelts == 0))
+#define apr_btable_elts(t) apr_table_elts(t)
+
+#define apr_is_empty_table(t) (((t) == NULL) \
+ || (((apr_array_header_t *)(t))->nelts == 0))
+#define apr_is_empty_btable(t) apr_is_empty_table(t)
-APR_EXPORT(apr_array_header_t *) apr_make_array(struct apr_pool_t *p, int nelts,
- int elt_size);
+APR_EXPORT(apr_array_header_t *) apr_make_array(struct apr_pool_t *p,
+ int nelts, int elt_size);
APR_EXPORT(void *) apr_push_array(apr_array_header_t *arr);
APR_EXPORT(void) apr_array_cat(apr_array_header_t *dst,
const apr_array_header_t *src);
@@ -165,25 +219,44 @@
const apr_array_header_t *arr,
const char sep);
APR_EXPORT(apr_table_t *) apr_make_table(struct apr_pool_t *p, int nelts);
-APR_EXPORT(apr_table_t *) apr_copy_table(struct apr_pool_t *p, const apr_table_t *t);
+APR_EXPORT(apr_btable_t *) apr_make_btable(struct apr_pool_t *p, int nelts);
+APR_EXPORT(apr_table_t *) apr_copy_table(struct apr_pool_t *p,
+ const apr_table_t *t);
+APR_EXPORT(apr_btable_t *) apr_copy_btable(struct apr_pool_t *p,
+ const apr_btable_t *t);
APR_EXPORT(void) apr_clear_table(apr_table_t *t);
+APR_EXPORT(void) apr_clear_btable(apr_btable_t *t);
APR_EXPORT(const char *) apr_table_get(const apr_table_t *t, const char *key);
+APR_EXPORT(const apr_item_t *) apr_btable_get(const apr_btable_t *t,
+ const char *key);
APR_EXPORT(void) apr_table_set(apr_table_t *t, const char *key,
const char *val);
+APR_EXPORT(void) apr_btable_set(apr_btable_t *t, const char *key,
+ size_t size, const void *val);
APR_EXPORT(void) apr_table_setn(apr_table_t *t, const char *key,
const char *val);
+APR_EXPORT(void) apr_btable_setn(apr_btable_t *t, const char *key,
+ size_t size, const void *val);
APR_EXPORT(void) apr_table_unset(apr_table_t *t, const char *key);
+APR_EXPORT(void) apr_btable_unset(apr_btable_t *t, const char *key);
APR_EXPORT(void) apr_table_merge(apr_table_t *t, const char *key,
const char *val);
APR_EXPORT(void) apr_table_mergen(apr_table_t *t, const char *key,
const char *val);
APR_EXPORT(void) apr_table_add(apr_table_t *t, const char *key,
const char *val);
+APR_EXPORT(void) apr_btable_add(apr_btable_t *t, const char *key,
+ size_t size, const void *val);
APR_EXPORT(void) apr_table_addn(apr_table_t *t, const char *key,
const char *val);
+APR_EXPORT(void) apr_btable_addn(apr_btable_t *t, const char *key,
+ size_t size, const void *val);
APR_EXPORT(apr_table_t *) apr_overlay_tables(struct apr_pool_t *p,
const apr_table_t *overlay,
const apr_table_t *base);
+APR_EXPORT(apr_btable_t *) apr_overlay_btables(struct apr_pool_t *p,
+ const apr_btable_t *overlay,
+ const apr_btable_t *base);
APR_EXPORT(void)
apr_table_do(int (*comp) (void *, const char *, const char *),
void *rec, const apr_table_t *t, ...);
@@ -192,27 +265,27 @@
void *rec, const apr_table_t *t, va_list);
/* Conceptually, apr_overlap_tables does this:
-
- apr_array_header_t *barr = apr_table_elts(b);
- apr_table_entry_t *belt = (apr_table_entry_t *)barr->elts;
- int i;
-
- for (i = 0; i < barr->nelts; ++i) {
- if (flags & apr_OVERLAP_TABLES_MERGE) {
- apr_table_mergen(a, belt[i].key, belt[i].val);
- }
- else {
- apr_table_setn(a, belt[i].key, belt[i].val);
- }
- }
-
- Except that it is more efficient (less space and cpu-time) especially
- when b has many elements.
-
- Notice the assumptions on the keys and values in b -- they must be
- in an ancestor of a's pool. In practice b and a are usually from
- the same pool.
-*/
+ *
+ * apr_array_header_t *barr = apr_table_elts(b);
+ * apr_table_entry_t *belt = (apr_table_entry_t *)barr->elts;
+ * int i;
+ *
+ * for (i = 0; i < barr->nelts; ++i) {
+ * if (flags & apr_OVERLAP_TABLES_MERGE) {
+ * apr_table_mergen(a, belt[i].key, belt[i].val);
+ * }
+ * else {
+ * apr_table_setn(a, belt[i].key, belt[i].val);
+ * }
+ * }
+ *
+ * Except that it is more efficient (less space and cpu-time) especially
+ * when b has many elements.
+ *
+ * Notice the assumptions on the keys and values in b -- they must be
+ * in an ancestor of a's pool. In practice b and a are usually from
+ * the same pool.
+ */
#define APR_OVERLAP_TABLES_SET (0)
#define APR_OVERLAP_TABLES_MERGE (1)
APR_EXPORT(void) apr_overlap_tables(apr_table_t *a, const apr_table_t *b,
1.5 +247 -0 apache-2.0/src/lib/apr/tables/apr_tables.c
Index: apr_tables.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/tables/apr_tables.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -u -r1.4 -r1.5
--- apr_tables.c 2000/08/06 06:07:27 1.4
+++ apr_tables.c 2000/08/22 21:55:34 1.5
@@ -305,6 +305,17 @@
return t;
}
+APR_EXPORT(apr_btable_t *) apr_make_btable(apr_pool_t *p, int nelts)
+{
+ apr_btable_t *t = apr_palloc(p, sizeof(apr_btable_t));
+
+ make_array_core(&t->a, p, nelts, sizeof(apr_btable_entry_t));
+#ifdef MAKE_TABLE_PROFILE
+ t->creator = __builtin_return_address(0);
+#endif
+ return t;
+}
+
APR_EXPORT(apr_table_t *) apr_copy_table(apr_pool_t *p, const apr_table_t *t)
{
apr_table_t *new = apr_palloc(p, sizeof(apr_table_t));
@@ -324,11 +335,36 @@
return new;
}
+APR_EXPORT(apr_btable_t *) apr_copy_btable(apr_pool_t *p,
+ const apr_btable_t *t)
+{
+ apr_btable_t *new = apr_palloc(p, sizeof(apr_btable_entry_t));
+
+#ifdef POOL_DEBUG
+ /* we don't copy keys and values, so it's necessary that t->a.pool
+ * have a life span at least as long as p
+ */
+ if (!apr_pool_is_ancestor(t->a.cont, p)) {
+ fprintf(stderr, "copy_btable: t's pool is not an ancestor of p\n");
+ abort();
+ }
+#endif
+ make_array_core(&new->a, p, t->a.nalloc, sizeof(apr_btable_entry_t));
+ memcpy(new->a.elts, t->a.elts, t->a.nelts * sizeof(apr_btable_entry_t));
+ new->a.nelts = t->a.nelts;
+ return new;
+}
+
APR_EXPORT(void) apr_clear_table(apr_table_t *t)
{
t->a.nelts = 0;
}
+APR_EXPORT(void) apr_clear_btable(apr_btable_t *t)
+{
+ t->a.nelts = 0;
+}
+
APR_EXPORT(const char *) apr_table_get(const apr_table_t *t, const char *key)
{
apr_table_entry_t *elts = (apr_table_entry_t *) t->a.elts;
@@ -347,6 +383,25 @@
return NULL;
}
+APR_EXPORT(const apr_item_t *) apr_btable_get(const apr_btable_t *t,
+ const char *key)
+{
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+ int i;
+
+ if (key == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < t->a.nelts; ++i) {
+ if (!strcasecmp(elts[i].key, key)) {
+ return elts[i].val;
+ }
+ }
+
+ return NULL;
+}
+
APR_EXPORT(void) apr_table_set(apr_table_t *t, const char *key,
const char *val)
{
@@ -381,6 +436,46 @@
}
}
+APR_EXPORT(void) apr_btable_set(apr_btable_t *t, const char *key,
+ size_t size, const void *val)
+{
+ register int i, j, k;
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+ apr_item_t *item;
+ int done = 0;
+
+ item = apr_pcalloc(t->a.cont, sizeof(apr_item_t));
+ item->size = size;
+ item->data = apr_pcalloc(t->a.cont, size);
+ memcpy(item->data, val, size);
+
+ for (i = 0; i < t->a.nelts; ) {
+ if (!strcasecmp(elts[i].key, key)) {
+ if (!done) {
+ elts[i].val = item;
+ done = 1;
+ ++i;
+ }
+ else { /* delete an extraneous element */
+ for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
+ elts[j].key = elts[k].key;
+ elts[j].val = elts[k].val;
+ }
+ --t->a.nelts;
+ }
+ }
+ else {
+ ++i;
+ }
+ }
+
+ if (!done) {
+ elts = (apr_btable_entry_t *) table_push((apr_btable_t *) t);
+ elts->key = apr_pstrdup(t->a.cont, key);
+ elts->val = item;
+ }
+}
+
APR_EXPORT(void) apr_table_setn(apr_table_t *t, const char *key,
const char *val)
{
@@ -428,6 +523,58 @@
}
}
+APR_EXPORT(void) apr_btable_setn(apr_btable_t *t, const char *key,
+ size_t size, const void *val)
+{
+ register int i, j, k;
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+ int done = 0;
+ apr_item_t *item;
+
+#ifdef POOL_DEBUG
+ {
+ if (!apr_pool_is_ancestor(apr_find_pool(key), t->a.cont)) {
+ fprintf(stderr, "table_set: key not in ancestor pool of t\n");
+ abort();
+ }
+ if (!apr_pool_is_ancestor(apr_find_pool(val), t->a.cont)) {
+ fprintf(stderr, "table_set: val not in ancestor pool of t\n");
+ abort();
+ }
+ }
+#endif
+
+ item = (apr_item_t *) apr_pcalloc(t->a.cont, size);
+ item->size = size;
+ item->data = (void *)val;
+
+ for (i = 0; i < t->a.nelts; ) {
+ if (!strcasecmp(elts[i].key, key)) {
+ if (!done) {
+ elts[i].val = item;
+ done = 1;
+ ++i;
+ }
+ else { /* delete an extraneous element */
+ for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
+ elts[j].key = elts[k].key;
+ elts[j].val = elts[k].val;
+ }
+ --t->a.nelts;
+ }
+ }
+ else {
+ ++i;
+ }
+ }
+
+ if (!done) {
+ elts = (apr_btable_entry_t *) table_push((apr_table_t *)t);
+ elts->key = (char *)key;
+ elts->val = item;
+ }
+}
+
APR_EXPORT(void) apr_table_unset(apr_table_t *t, const char *key)
{
register int i, j, k;
@@ -453,6 +600,31 @@
}
}
+APR_EXPORT(void) apr_btable_unset(apr_btable_t *t, const char *key)
+{
+ register int i, j, k;
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+
+ for (i = 0; i < t->a.nelts; ) {
+ if (!strcasecmp(elts[i].key, key)) {
+
+ /* found an element to skip over
+ * there are any number of ways to remove an element from
+ * a contiguous block of memory. I've chosen one that
+ * doesn't do a memcpy/bcopy/array_delete, *shrug*...
+ */
+ for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
+ elts[j].key = elts[k].key;
+ elts[j].val = elts[k].val;
+ }
+ --t->a.nelts;
+ }
+ else {
+ ++i;
+ }
+ }
+}
+
APR_EXPORT(void) apr_table_merge(apr_table_t *t, const char *key,
const char *val)
{
@@ -512,6 +684,21 @@
elts->val = apr_pstrdup(t->a.cont, val);
}
+APR_EXPORT(void) apr_btable_add(apr_btable_t *t, const char *key,
+ size_t size, const void *val)
+{
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+ apr_item_t *item;
+
+ item = (apr_item_t *) apr_pcalloc(t->a.cont, sizeof(apr_item_t));
+ item->size = size;
+ item->data = apr_pcalloc(t->a.cont, size);
+ memcpy(item->data, val, size);
+ elts = (apr_btable_entry_t *) table_push((apr_btable_t *)t);
+ elts->key = apr_pstrdup(t->a.cont, key);
+ elts->val = item;
+}
+
APR_EXPORT(void) apr_table_addn(apr_table_t *t, const char *key,
const char *val)
{
@@ -535,6 +722,34 @@
elts->val = (char *)val;
}
+APR_EXPORT(void) apr_btable_addn(apr_btable_t *t, const char *key,
+ size_t size, const void *val)
+{
+ apr_btable_entry_t *elts = (apr_btable_entry_t *) t->a.elts;
+ apr_item_t *item;
+
+#ifdef POOL_DEBUG
+ {
+ if (!apr_pool_is_ancestor(apr_find_pool(key), t->a.cont)) {
+ fprintf(stderr, "table_set: key not in ancestor pool of t\n");
+ abort();
+ }
+ if (!apr_pool_is_ancestor(apr_find_pool(val), t->a.cont)) {
+ fprintf(stderr, "table_set: key not in ancestor pool of t\n");
+ abort();
+ }
+ }
+#endif
+
+ item = (apr_item_t *) apr_pcalloc(t->a.cont, sizeof(apr_item_t));
+ item->size = size;
+ item->data = apr_pcalloc(t->a.cont, size);
+ memcpy(item->data, val, size);
+ elts = (apr_btable_entry_t *) table_push((apr_btable_t *)t);
+ elts->key = (char *)key;
+ elts->val = item;
+}
+
APR_EXPORT(apr_table_t *) apr_overlay_tables(apr_pool_t *p,
const apr_table_t *overlay,
const apr_table_t *base)
@@ -559,6 +774,38 @@
#endif
res = apr_palloc(p, sizeof(apr_table_t));
+ /* behave like append_arrays */
+ res->a.cont = p;
+ copy_array_hdr_core(&res->a, &overlay->a);
+ apr_array_cat(&res->a, &base->a);
+
+ return res;
+}
+
+APR_EXPORT(apr_btable_t *) apr_overlay_btables(apr_pool_t *p,
+ const apr_btable_t *overlay,
+ const apr_btable_t *base)
+{
+ apr_btable_t *res;
+
+#ifdef POOL_DEBUG
+ /* we don't copy keys and values, so it's necessary that
+ * overlay->a.pool and base->a.pool have a life span at least
+ * as long as p
+ */
+ if (!apr_pool_is_ancestor(overlay->a.cont, p)) {
+ fprintf(stderr,
+ "overlay_tables: overlay's pool is not an ancestor of p\n");
+ abort();
+ }
+ if (!apr_pool_is_ancestor(base->a.cont, p)) {
+ fprintf(stderr,
+ "overlay_tables: base's pool is not an ancestor of p\n");
+ abort();
+ }
+#endif
+
+ res = apr_palloc(p, sizeof(apr_btable_t));
/* behave like append_arrays */
res->a.cont = p;
copy_array_hdr_core(&res->a, &overlay->a);