📄 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_PROFILE
static 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 + -