jwoolley 2002/06/28 15:45:38 Modified: . CHANGES include apr_tables.h tables apr_tables.c Log: A compromise for now: changing the return type of apr_table_do() and apr_table_vdo() to return int instead of void so that the caller can know whether or not any of the iterations trigged an "early return". However, I've left the wacky old semantics of _vdo for a while. This solves my immediate need at least. Revision Changes Path 1.300 +4 -0 apr/CHANGES Index: CHANGES =================================================================== RCS file: /home/cvs/apr/CHANGES,v retrieving revision 1.299 retrieving revision 1.300 diff -u -d -u -r1.299 -r1.300 --- CHANGES 28 Jun 2002 11:38:50 -0000 1.299 +++ CHANGES 28 Jun 2002 22:45:37 -0000 1.300 @@ -1,5 +1,9 @@ Changes with APR b1 + *) apr_table_do() and apr_table_vdo() now return an int rather than + void to indicate whether or not any of its iterations returned 0. + [Cliff Woolley] + *) Fix the definition of union semun so that it is valid on systems where sizeof(long) != sizeof(int). This resolves a hang on HP-UX/Itanium. 1.30 +9 -4 apr/include/apr_tables.h Index: apr_tables.h =================================================================== RCS file: /home/cvs/apr/include/apr_tables.h,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -u -r1.29 -r1.30 --- apr_tables.h 28 Jun 2002 14:04:36 -0000 1.29 +++ apr_tables.h 28 Jun 2002 22:45:38 -0000 1.30 @@ -374,10 +374,12 @@ * @param ... The vararg. If this is NULL, then all elements in the table are * run through the function, otherwise only those whose key matches * are run. + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero * @see apr_table_do_callback_fn_t */ -APR_DECLARE_NONSTD(void) apr_table_do(apr_table_do_callback_fn_t *comp, - void *rec, const apr_table_t *t, ...); +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...); /** * Iterate over a table running the provided function once for every @@ -391,9 +393,12 @@ * @param vp The vararg table. If this is NULL, then all elements in the * table are run through the function, otherwise only those * whose key matches are run. + * @return FALSE if one of the comp() iterations returned zero; TRUE if all + * iterations returned non-zero + * @see apr_table_do_callback_fn_t */ -APR_DECLARE(void) apr_table_vdo(apr_table_do_callback_fn_t *comp, - void *rec, const apr_table_t *t, va_list); +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list); /** flag for overlap to use apr_table_setn */ #define APR_OVERLAP_TABLES_SET (0) 1.28 +47 -7 apr/tables/apr_tables.c Index: apr_tables.c =================================================================== RCS file: /home/cvs/apr/tables/apr_tables.c,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -u -r1.27 -r1.28 --- apr_tables.c 28 Jun 2002 14:04:36 -0000 1.27 +++ apr_tables.c 28 Jun 2002 22:45:38 -0000 1.28 @@ -695,21 +695,56 @@ * * So to make mod_file_cache easier to maintain, it's a good thing */ -APR_DECLARE_NONSTD(void) apr_table_do(apr_table_do_callback_fn_t *comp, - void *rec, const apr_table_t *t, ...) +APR_DECLARE_NONSTD(int) apr_table_do(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, ...) { + int rv; + va_list vp; va_start(vp, t); - apr_table_vdo(comp, rec, t, vp); - va_end(vp); + rv = apr_table_vdo(comp, rec, t, vp); + va_end(vp); + + return rv; } -APR_DECLARE(void) apr_table_vdo(apr_table_do_callback_fn_t *comp, - void *rec, const apr_table_t *t, va_list vp) +/* XXX: do the semantics of this routine make any sense? Right now, + * if the caller passed in a non-empty va_list of keys to search for, + * the "early termination" facility only terminates on *that* key; other + * keys will continue to process. Note that this only has any effect + * at all if there are multiple entries in the table with the same key, + * otherwise the called function can never effectively early-terminate + * this function, as the zero return value is effectively ignored. + * + * Note also that this behavior is at odds with the behavior seen if an + * empty va_list is passed in -- in that case, a zero return value terminates + * the entire apr_table_vdo (which is what I think should happen in + * both cases). + * + * If nobody objects soon, I'm going to change the order of the nested + * loops in this function so that any zero return value from the (*comp) + * function will cause a full termination of apr_table_vdo. I'm hesitant + * at the moment because these (funky) semantics have been around for a + * very long time, and although Apache doesn't seem to use them at all, + * some third-party vendor might. I can only think of one possible reason + * the existing semantics would make any sense, and it's very Apache-centric, + * which is this: if (*comp) is looking for matches of a particular + * substring in request headers (let's say it's looking for a particular + * cookie name in the Set-Cookie headers), then maybe it wants to be + * able to stop searching early as soon as it finds that one and move + * on to the next key. That's only an optimization of course, but changing + * the behavior of this function would mean that any code that tried + * to do that would stop working right. + * + * Sigh. --JCW, 06/28/02 + */ +APR_DECLARE(int) apr_table_vdo(apr_table_do_callback_fn_t *comp, + void *rec, const apr_table_t *t, va_list vp) { char *argp; apr_table_entry_t *elts = (apr_table_entry_t *) t->a.elts; - int rv, i; + int vdorv = 1, rv, i; + argp = va_arg(vp, char *); do { apr_uint32_t checksum = 0; @@ -723,7 +758,12 @@ rv = (*comp) (rec, elts[i].key, elts[i].val); } } + if (rv == 0) { + vdorv = 0; + } } while (argp && ((argp = va_arg(vp, char *)) != NULL)); + + return vdorv; } /* During apr_table_overlap(), we build an overlap key for