⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apr_tables.c

📁 apache的软件linux版本
💻 C
📖 第 1 页 / 共 3 页
字号:
    apr_table_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.pool, p)) {	fprintf(stderr,		"overlay_tables: overlay's pool is not an ancestor of p\n");	abort();    }    if (!apr_pool_is_ancestor(base->a.pool, p)) {	fprintf(stderr,		"overlay_tables: base's pool is not an ancestor of p\n");	abort();    }#endif    res = apr_palloc(p, sizeof(apr_table_t));    /* behave like append_arrays */    res->a.pool = p;    copy_array_hdr_core(&res->a, &overlay->a);    apr_array_cat(&res->a, &base->a);    table_reindex(res);    return res;}/* And now for something completely abstract ... * For each key value given as a vararg: *   run the function pointed to as *     int comp(void *r, char *key, char *value); *   on each valid key-value pair in the apr_table_t t that matches the vararg key, *   or once for every valid key-value pair if the vararg list is empty, *   until the function returns false (0) or we finish the table. * * Note that we restart the traversal for each vararg, which means that * duplicate varargs will result in multiple executions of the function * for each matching key.  Note also that if the vararg list is empty, * only one traversal will be made and will cut short if comp returns 0. * * Note that the table_get and table_merge functions assume that each key in * the apr_table_t is unique (i.e., no multiple entries with the same key).  This * function does not make that assumption, since it (unfortunately) isn't * true for some of Apache's tables. * * Note that rec is simply passed-on to the comp function, so that the * caller can pass additional info for the task. * * ADDENDUM for apr_table_vdo(): *  * The caching api will allow a user to walk the header values: * * apr_status_t apr_cache_el_header_walk(apr_cache_el *el,  *    int (*comp)(void *, const char *, const char *), void *rec, ...); * * So it can be ..., however from there I use a  callback that use a va_list: * * apr_status_t (*cache_el_header_walk)(apr_cache_el *el,  *    int (*comp)(void *, const char *, const char *), void *rec, va_list); * * To pass those ...'s on down to the actual module that will handle walking * their headers, in the file case this is actually just an apr_table - and * rather than reimplementing apr_table_do (which IMHO would be bad) I just * called it with the va_list. For mod_shmem_cache I don't need it since I * can't use apr_table's, but mod_file_cache should (though a good hash would * be better, but that's a different issue :).  * * So to make mod_file_cache easier to maintain, it's a good thing */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);    rv = apr_table_vdo(comp, rec, t, vp);    va_end(vp);    return rv;} /* 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 vdorv = 1;    argp = va_arg(vp, char *);    do {        int rv = 1, i;        if (argp) {            /* Scan for entries that match the next key */            int hash = TABLE_HASH(argp);            if (TABLE_INDEX_IS_INITIALIZED(t, hash)) {                apr_uint32_t checksum;                COMPUTE_KEY_CHECKSUM(argp, checksum);                for (i = t->index_first[hash];                     rv && (i <= t->index_last[hash]); ++i) {                    if (elts[i].key && (checksum == elts[i].key_checksum) &&                                        !strcasecmp(elts[i].key, argp)) {                        rv = (*comp) (rec, elts[i].key, elts[i].val);                    }                }            }        }        else {            /* Scan the entire table */            for (i = 0; rv && (i < t->a.nelts); ++i) {                if (elts[i].key) {                    rv = (*comp) (rec, elts[i].key, elts[i].val);                }            }        }        if (rv == 0) {            vdorv = 0;        }    } while (argp && ((argp = va_arg(vp, char *)) != NULL));    return vdorv;}static apr_table_entry_t **table_mergesort(apr_pool_t *pool,                                           apr_table_entry_t **values, int n){    /* Bottom-up mergesort, based on design in Sedgewick's "Algorithms     * in C," chapter 8     */    apr_table_entry_t **values_tmp =        (apr_table_entry_t **)apr_palloc(pool, n * sizeof(apr_table_entry_t*));    int i;    int blocksize;    /* First pass: sort pairs of elements (blocksize=1) */    for (i = 0; i + 1 < n; i += 2) {        if (strcasecmp(values[i]->key, values[i + 1]->key) > 0) {            apr_table_entry_t *swap = values[i];            values[i] = values[i + 1];            values[i + 1] = swap;        }    }    /* Merge successively larger blocks */    blocksize = 2;    while (blocksize < n) {        apr_table_entry_t **dst = values_tmp;        int next_start;        apr_table_entry_t **swap;        /* Merge consecutive pairs blocks of the next blocksize.         * Within a block, elements are in sorted order due to         * the previous iteration.         */        for (next_start = 0; next_start + blocksize < n;             next_start += (blocksize + blocksize)) {            int block1_start = next_start;            int block2_start = block1_start + blocksize;            int block1_end = block2_start;            int block2_end = block2_start + blocksize;            if (block2_end > n) {                /* The last block may be smaller than blocksize */                block2_end = n;            }            for (;;) {                /* Merge the next two blocks:                 * Pick the smaller of the next element from                 * block 1 and the next element from block 2.                 * Once either of the blocks is emptied, copy                 * over all the remaining elements from the                 * other block                 */                if (block1_start == block1_end) {                    for (; block2_start < block2_end; block2_start++) {                        *dst++ = values[block2_start];                    }                    break;                }                else if (block2_start == block2_end) {                    for (; block1_start < block1_end; block1_start++) {                        *dst++ = values[block1_start];                    }                    break;                }                if (strcasecmp(values[block1_start]->key,                               values[block2_start]->key) > 0) {                    *dst++ = values[block2_start++];                }                else {                    *dst++ = values[block1_start++];                }            }        }        /* If n is not a multiple of 2*blocksize, some elements         * will be left over at the end of the array.         */        for (i = dst - values_tmp; i < n; i++) {            values_tmp[i] = values[i];        }        /* The output array of this pass becomes the input         * array of the next pass, and vice versa         */        swap = values_tmp;        values_tmp = values;        values = swap;        blocksize += blocksize;    }    return values;}APR_DECLARE(void) apr_table_compress(apr_table_t *t, unsigned flags){    apr_table_entry_t **sort_array;    apr_table_entry_t **sort_next;    apr_table_entry_t **sort_end;    apr_table_entry_t *table_next;    apr_table_entry_t **last;    int i;    int dups_found;    if (t->a.nelts <= 1) {        return;    }    /* Copy pointers to all the table elements into an     * array and sort to allow for easy detection of     * duplicate keys     */    sort_array = (apr_table_entry_t **)        apr_palloc(t->a.pool, t->a.nelts * sizeof(apr_table_entry_t*));    sort_next = sort_array;    table_next = (apr_table_entry_t *)t->a.elts;    i = t->a.nelts;    do {        *sort_next++ = table_next++;    } while (--i);    /* Note: the merge is done with mergesort instead of quicksort     * because mergesort is a stable sort and runs in n*log(n)     * time regardless of its inputs (quicksort is quadratic in     * the worst case)     */    sort_array = table_mergesort(t->a.pool, sort_array, t->a.nelts);    /* Process any duplicate keys */    dups_found = 0;    sort_next = sort_array;    sort_end = sort_array + t->a.nelts;    last = sort_next++;    while (sort_next < sort_end) {        if (((*sort_next)->key_checksum == (*last)->key_checksum) &&            !strcasecmp((*sort_next)->key, (*last)->key)) {            apr_table_entry_t **dup_last = sort_next + 1;            dups_found = 1;            while ((dup_last < sort_end) &&                   ((*dup_last)->key_checksum == (*last)->key_checksum) &&                   !strcasecmp((*dup_last)->key, (*last)->key)) {                dup_last++;            }            dup_last--; /* Elements from last through dup_last, inclusive,                         * all have the same key                         */            if (flags == APR_OVERLAP_TABLES_MERGE) {                apr_size_t len = 0;                apr_table_entry_t **next = last;                char *new_val;                char *val_dst;                do {                    len += strlen((*next)->val);                    len += 2; /* for ", " or trailing null */                } while (++next <= dup_last);                new_val = (char *)apr_palloc(t->a.pool, len);                val_dst = new_val;                next = last;                for (;;) {                    strcpy(val_dst, (*next)->val);                    val_dst += strlen((*next)->val);                    next++;                    if (next > dup_last) {                        *val_dst = 0;                        break;                    }                    else {                        *val_dst++ = ',';                        *val_dst++ = ' ';                    }                }                (*last)->val = new_val;            }            else { /* overwrite */                (*last)->val = (*dup_last)->val;            }            do {                (*sort_next)->key = NULL;            } while (++sort_next <= dup_last);        }        else {            last = sort_next++;        }    }    /* Shift elements to the left to fill holes left by removing duplicates */    if (dups_found) {        apr_table_entry_t *src = (apr_table_entry_t *)t->a.elts;        apr_table_entry_t *dst = (apr_table_entry_t *)t->a.elts;        apr_table_entry_t *last_elt = src + t->a.nelts;        do {            if (src->key) {                *dst++ = *src;            }        } while (++src < last_elt);        t->a.nelts -= (last_elt - dst);    }    table_reindex(t);}static void apr_table_cat(apr_table_t *t, const apr_table_t *s){    const int n = t->a.nelts;    register int idx;    apr_array_cat(&t->a,&s->a);    if (n == 0) {        memcpy(t->index_first,s->index_first,sizeof(int) * TABLE_HASH_SIZE);        memcpy(t->index_last, s->index_last, sizeof(int) * TABLE_HASH_SIZE);        t->index_initialized = s->index_initialized;        return;    }    for (idx = 0; idx < TABLE_HASH_SIZE; ++idx) {        if (TABLE_INDEX_IS_INITIALIZED(s, idx)) {            t->index_last[idx] = s->index_last[idx] + n;            if (!TABLE_INDEX_IS_INITIALIZED(t, idx)) {                t->index_first[idx] = s->index_first[idx] + n;            }        }    }    t->index_initialized |= s->index_initialized;}APR_DECLARE(void) apr_table_overlap(apr_table_t *a, const apr_table_t *b,				    unsigned flags){    const int m = a->a.nelts;    const int n = b->a.nelts;    apr_pool_t *p = b->a.pool;    if (m + n == 0) {        return;    }    /* copy (extend) a using b's pool */    if (a->a.pool != p) {        make_array_core(&a->a, p, m+n, sizeof(apr_table_entry_t), 0);    }    apr_table_cat(a, b);    apr_table_compress(a, flags);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -