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);