📄 apr_tables.c
字号:
#include <stdio.h>/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * Resource allocation code... the code here is responsible for making * sure that nothing leaks. * * rst --- 4/95 --- 6/95 */#include "apr_private.h"#include "apr_general.h"#include "apr_pools.h"#include "apr_tables.h"#include "apr_strings.h"#include "apr_lib.h"#if APR_HAVE_STDLIB_H#include <stdlib.h>#endif#if APR_HAVE_STRING_H#include <string.h>#endif#if APR_HAVE_STRINGS_H#include <strings.h>#endif/***************************************************************** * This file contains array and apr_table_t functions only. *//***************************************************************** * * The 'array' functions... */static void make_array_core(apr_array_header_t *res, apr_pool_t *p, int nelts, int elt_size, int clear){ /* * Assure sanity if someone asks for * array of zero elts. */ if (nelts < 1) { nelts = 1; } if (clear) { res->elts = apr_pcalloc(p, nelts * elt_size); } else { res->elts = apr_palloc(p, nelts * elt_size); } res->pool = p; res->elt_size = elt_size; res->nelts = 0; /* No active elements yet... */ res->nalloc = nelts; /* ...but this many allocated */}APR_DECLARE(int) apr_is_empty_array(const apr_array_header_t *a){ return ((a == NULL) || (a->nelts == 0));}APR_DECLARE(apr_array_header_t *) apr_array_make(apr_pool_t *p, int nelts, int elt_size){ apr_array_header_t *res; res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); make_array_core(res, p, nelts, elt_size, 1); return res;}APR_DECLARE(void *) apr_array_pop(apr_array_header_t *arr){ if (apr_is_empty_array(arr)) { return NULL; } return arr->elts + (arr->elt_size * (--arr->nelts));}APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr){ if (arr->nelts == arr->nalloc) { int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; char *new_data; new_data = apr_palloc(arr->pool, arr->elt_size * new_size); memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size); memset(new_data + arr->nalloc * arr->elt_size, 0, arr->elt_size * (new_size - arr->nalloc)); arr->elts = new_data; arr->nalloc = new_size; } ++arr->nelts; return arr->elts + (arr->elt_size * (arr->nelts - 1));}static void *apr_array_push_noclear(apr_array_header_t *arr){ if (arr->nelts == arr->nalloc) { int new_size = (arr->nalloc <= 0) ? 1 : arr->nalloc * 2; char *new_data; new_data = apr_palloc(arr->pool, arr->elt_size * new_size); memcpy(new_data, arr->elts, arr->nalloc * arr->elt_size); arr->elts = new_data; arr->nalloc = new_size; } ++arr->nelts; return arr->elts + (arr->elt_size * (arr->nelts - 1));}APR_DECLARE(void) apr_array_cat(apr_array_header_t *dst, const apr_array_header_t *src){ int elt_size = dst->elt_size; if (dst->nelts + src->nelts > dst->nalloc) { int new_size = (dst->nalloc <= 0) ? 1 : dst->nalloc * 2; char *new_data; while (dst->nelts + src->nelts > new_size) { new_size *= 2; } new_data = apr_pcalloc(dst->pool, elt_size * new_size); memcpy(new_data, dst->elts, dst->nalloc * elt_size); dst->elts = new_data; dst->nalloc = new_size; } memcpy(dst->elts + dst->nelts * elt_size, src->elts, elt_size * src->nelts); dst->nelts += src->nelts;}APR_DECLARE(apr_array_header_t *) apr_array_copy(apr_pool_t *p, const apr_array_header_t *arr){ apr_array_header_t *res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); make_array_core(res, p, arr->nalloc, arr->elt_size, 0); memcpy(res->elts, arr->elts, arr->elt_size * arr->nelts); res->nelts = arr->nelts; memset(res->elts + res->elt_size * res->nelts, 0, res->elt_size * (res->nalloc - res->nelts)); return res;}/* This cute function copies the array header *only*, but arranges * for the data section to be copied on the first push or arraycat. * It's useful when the elements of the array being copied are * read only, but new stuff *might* get added on the end; we have the * overhead of the full copy only where it is really needed. */static APR_INLINE void copy_array_hdr_core(apr_array_header_t *res, const apr_array_header_t *arr){ res->elts = arr->elts; res->elt_size = arr->elt_size; res->nelts = arr->nelts; res->nalloc = arr->nelts; /* Force overflow on push */}APR_DECLARE(apr_array_header_t *) apr_array_copy_hdr(apr_pool_t *p, const apr_array_header_t *arr){ apr_array_header_t *res; res = (apr_array_header_t *) apr_palloc(p, sizeof(apr_array_header_t)); res->pool = p; copy_array_hdr_core(res, arr); return res;}/* The above is used here to avoid consing multiple new array bodies... */APR_DECLARE(apr_array_header_t *) apr_array_append(apr_pool_t *p, const apr_array_header_t *first, const apr_array_header_t *second){ apr_array_header_t *res = apr_array_copy_hdr(p, first); apr_array_cat(res, second); return res;}/* apr_array_pstrcat generates a new string from the apr_pool_t containing * the concatenated sequence of substrings referenced as elements within * the array. The string will be empty if all substrings are empty or null, * or if there are no elements in the array. * If sep is non-NUL, it will be inserted between elements as a separator. */APR_DECLARE(char *) apr_array_pstrcat(apr_pool_t *p, const apr_array_header_t *arr, const char sep){ char *cp, *res, **strpp; apr_size_t len; int i; if (arr->nelts <= 0 || arr->elts == NULL) { /* Empty table? */ return (char *) apr_pcalloc(p, 1); } /* Pass one --- find length of required string */ len = 0; for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { if (strpp && *strpp != NULL) { len += strlen(*strpp); } if (++i >= arr->nelts) { break; } if (sep) { ++len; } } /* Allocate the required string */ res = (char *) apr_palloc(p, len + 1); cp = res; /* Pass two --- copy the argument strings into the result space */ for (i = 0, strpp = (char **) arr->elts; ; ++strpp) { if (strpp && *strpp != NULL) { len = strlen(*strpp); memcpy(cp, *strpp, len); cp += len; } if (++i >= arr->nelts) { break; } if (sep) { *cp++ = sep; } } *cp = '\0'; /* Return the result string */ return res;}/***************************************************************** * * The "table" functions. */#if APR_CHARSET_EBCDIC#define CASE_MASK 0xbfbfbfbf#else#define CASE_MASK 0xdfdfdfdf#endif#define TABLE_HASH_SIZE 32#define TABLE_INDEX_MASK 0x1f#define TABLE_HASH(key) (TABLE_INDEX_MASK & *(unsigned char *)(key))#define TABLE_INDEX_IS_INITIALIZED(t, i) ((t)->index_initialized & (1 << (i)))#define TABLE_SET_INDEX_INITIALIZED(t, i) ((t)->index_initialized |= (1 << (i)))/* Compute the "checksum" for a key, consisting of the first * 4 bytes, normalized for case-insensitivity and packed into * an int...this checksum allows us to do a single integer * comparison as a fast check to determine whether we can * skip a strcasecmp */#define COMPUTE_KEY_CHECKSUM(key, checksum) \{ \ const char *k = (key); \ apr_uint32_t c = (apr_uint32_t)*k; \ (checksum) = c; \ (checksum) <<= 8; \ if (c) { \ c = (apr_uint32_t)*++k; \ checksum |= c; \ } \ (checksum) <<= 8; \ if (c) { \ c = (apr_uint32_t)*++k; \ checksum |= c; \ } \ (checksum) <<= 8; \ if (c) { \ c = (apr_uint32_t)*++k; \ checksum |= c; \ } \ checksum &= CASE_MASK; \}/** 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 *... * they should use the apr_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 /* An index to speed up table lookups. The way this works is: * - Take the requested key and compute its checksum * - Hash the checksum into the index: * - index_first[TABLE_HASH(checksum)] is the offset within * the table of the first entry with that key checksum * - index_last[TABLE_HASH(checksum)] is the offset within * the table of the first entry with that key checksum * - If (and only if) there is no entry in the table whose * checksum hashes to index element i, then the i'th bit * of index_initialized will be zero. (Check this before * trying to use index_first[i] or index_last[i]!) */ apr_uint32_t index_initialized; int index_first[TABLE_HASH_SIZE]; int index_last[TABLE_HASH_SIZE];};/* * NOTICE: if you tweak this you should look at is_empty_table() * and table_elts() in alloc.h */#ifdef MAKE_TABLE_PROFILEstatic apr_table_entry_t *table_push(apr_table_t *t){ if (t->a.nelts == t->a.nalloc) { return NULL; } return (apr_table_entry_t *) apr_array_push_noclear(&t->a);}#else /* MAKE_TABLE_PROFILE */#define table_push(t) ((apr_table_entry_t *) apr_array_push_noclear(&(t)->a))#endif /* MAKE_TABLE_PROFILE */APR_DECLARE(const apr_array_header_t *) apr_table_elts(const apr_table_t *t){ return (const apr_array_header_t *)t;}APR_DECLARE(int) apr_is_empty_table(const apr_table_t *t){ return ((t == NULL) || (t->a.nelts == 0));}APR_DECLARE(apr_table_t *) apr_table_make(apr_pool_t *p, int nelts){ apr_table_t *t = apr_palloc(p, sizeof(apr_table_t)); make_array_core(&t->a, p, nelts, sizeof(apr_table_entry_t), 0);#ifdef MAKE_TABLE_PROFILE t->creator = __builtin_return_address(0);#endif t->index_initialized = 0; return t;}APR_DECLARE(apr_table_t *) apr_table_copy(apr_pool_t *p, const apr_table_t *t){ apr_table_t *new = apr_palloc(p, sizeof(apr_table_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.pool, p)) { fprintf(stderr, "copy_table: t's pool is not an ancestor of p\n"); abort(); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -