feat:replace boost library with C++11 std library

This commit is contained in:
Livox-SDK
2020-04-01 20:53:55 +08:00
parent 6d06233944
commit d3258bbd97
1936 changed files with 241862 additions and 60153 deletions
+315
View File
@@ -0,0 +1,315 @@
/* 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.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_private.h"
#include "apr_lib.h"
#if APR_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if APR_HAVE_STRING_H
#include <string.h>
#endif
#if APR_HAVE_CTYPE_H
#include <ctype.h>
#endif
/*
* Apache's "replacement" for the strncpy() function. We roll our
* own to implement these specific changes:
* (1) strncpy() doesn't always null terminate and we want it to.
* (2) strncpy() null fills, which is bogus, esp. when copy 8byte
* strings into 8k blocks.
* (3) Instead of returning the pointer to the beginning of
* the destination string, we return a pointer to the
* terminating '\0' to allow us to "check" for truncation
* (4) If src is NULL, null terminate dst (empty string copy)
*
* apr_cpystrn() follows the same call structure as strncpy().
*/
APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size)
{
char *d = dst, *end;
if (dst_size == 0) {
return (dst);
}
if (src) {
end = dst + dst_size - 1;
for (; d < end; ++d, ++src) {
if (!(*d = *src)) {
return (d);
}
}
}
*d = '\0'; /* always null terminate */
return (d);
}
/*
* This function provides a way to parse a generic argument string
* into a standard argv[] form of argument list. It respects the
* usual "whitespace" and quoteing rules. In the future this could
* be expanded to include support for the apr_call_exec command line
* string processing (including converting '+' to ' ' and doing the
* url processing. It does not currently support this function.
*
* token_context: Context from which pool allocations will occur.
* arg_str: Input argument string for conversion to argv[].
* argv_out: Output location. This is a pointer to an array
* of pointers to strings (ie. &(char *argv[]).
* This value will be allocated from the contexts
* pool and filled in with copies of the tokens
* found during parsing of the arg_str.
*/
APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str,
char ***argv_out,
apr_pool_t *token_context)
{
const char *cp;
const char *ct;
char *cleaned, *dirty;
int escaped;
int isquoted, numargs = 0, argnum;
#define SKIP_WHITESPACE(cp) \
for ( ; *cp == ' ' || *cp == '\t'; ) { \
cp++; \
};
#define CHECK_QUOTATION(cp,isquoted) \
isquoted = 0; \
if (*cp == '"') { \
isquoted = 1; \
cp++; \
} \
else if (*cp == '\'') { \
isquoted = 2; \
cp++; \
}
/* DETERMINE_NEXTSTRING:
* At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE.
* NULL implies the argument string has been fully traversed.
*/
#define DETERMINE_NEXTSTRING(cp,isquoted) \
for ( ; *cp != '\0'; cp++) { \
if ( (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \
*(cp+1) == '"' || *(cp+1) == '\''))) { \
cp++; \
continue; \
} \
if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \
|| (isquoted == 1 && *cp == '"') \
|| (isquoted == 2 && *cp == '\'') ) { \
break; \
} \
}
/* REMOVE_ESCAPE_CHARS:
* Compresses the arg string to remove all of the '\' escape chars.
* The final argv strings should not have any extra escape chars in it.
*/
#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \
escaped = 0; \
while(*dirty) { \
if (!escaped && *dirty == '\\') { \
escaped = 1; \
} \
else { \
escaped = 0; \
*cleaned++ = *dirty; \
} \
++dirty; \
} \
*cleaned = 0; /* last line of macro... */
cp = arg_str;
SKIP_WHITESPACE(cp);
ct = cp;
/* This is ugly and expensive, but if anyone wants to figure a
* way to support any number of args without counting and
* allocating, please go ahead and change the code.
*
* Must account for the trailing NULL arg.
*/
numargs = 1;
while (*ct != '\0') {
CHECK_QUOTATION(ct, isquoted);
DETERMINE_NEXTSTRING(ct, isquoted);
if (*ct != '\0') {
ct++;
}
numargs++;
SKIP_WHITESPACE(ct);
}
*argv_out = apr_palloc(token_context, numargs * sizeof(char*));
/* determine first argument */
for (argnum = 0; argnum < (numargs-1); argnum++) {
SKIP_WHITESPACE(cp);
CHECK_QUOTATION(cp, isquoted);
ct = cp;
DETERMINE_NEXTSTRING(cp, isquoted);
cp++;
(*argv_out)[argnum] = apr_palloc(token_context, cp - ct);
apr_cpystrn((*argv_out)[argnum], ct, cp - ct);
cleaned = dirty = (*argv_out)[argnum];
REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped);
}
(*argv_out)[argnum] = NULL;
return APR_SUCCESS;
}
/* Filepath_name_get returns the final element of the pathname.
* Using the current platform's filename syntax.
* "/foo/bar/gum" -> "gum"
* "/foo/bar/gum/" -> ""
* "gum" -> "gum"
* "wi\\n32\\stuff" -> "stuff
*
* Corrected Win32 to accept "a/b\\stuff", "a:stuff"
*/
APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname)
{
const char path_separator = '/';
const char *s = strrchr(pathname, path_separator);
#ifdef WIN32
const char path_separator_win = '\\';
const char drive_separator_win = ':';
const char *s2 = strrchr(pathname, path_separator_win);
if (s2 > s) s = s2;
if (!s) s = strrchr(pathname, drive_separator_win);
#endif
return s ? ++s : pathname;
}
/* length of dest assumed >= length of src
* collapse in place (src == dest) is legal.
* returns terminating null ptr to dest string.
*/
APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src)
{
while (*src) {
if (!apr_isspace(*src))
*dest++ = *src;
++src;
}
*dest = 0;
return (dest);
}
#if !APR_HAVE_STRDUP
char *strdup(const char *str)
{
char *sdup;
size_t len = strlen(str) + 1;
sdup = (char *) malloc(len);
if (sdup == NULL)
return NULL;
memcpy(sdup, str, len);
return sdup;
}
#endif
/* The following two routines were donated for SVR4 by Andreas Vogel */
#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP)
int strcasecmp(const char *a, const char *b)
{
const char *p = a;
const char *q = b;
for (p = a, q = b; *p && *q; p++, q++) {
int diff = apr_tolower(*p) - apr_tolower(*q);
if (diff)
return diff;
}
if (*p)
return 1; /* p was longer than q */
if (*q)
return -1; /* p was shorter than q */
return 0; /* Exact match */
}
#endif
#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP)
int strncasecmp(const char *a, const char *b, size_t n)
{
const char *p = a;
const char *q = b;
for (p = a, q = b; /*NOTHING */ ; p++, q++) {
int diff;
if (p == a + n)
return 0; /* Match up to n characters */
if (!(*p && *q))
return *p - *q;
diff = apr_tolower(*p) - apr_tolower(*q);
if (diff)
return diff;
}
/*NOTREACHED */
}
#endif
/* The following routine was donated for UTS21 by dwd@bell-labs.com */
#if (!APR_HAVE_STRSTR)
char *strstr(char *s1, char *s2)
{
char *p1, *p2;
if (*s2 == '\0') {
/* an empty s2 */
return(s1);
}
while((s1 = strchr(s1, *s2)) != NULL) {
/* found first character of s2, see if the rest matches */
p1 = s1;
p2 = s2;
while (*++p1 == *++p2) {
if (*p1 == '\0') {
/* both strings ended together */
return(s1);
}
}
if (*p2 == '\0') {
/* second string ended, a match */
break;
}
/* didn't find a match here, try starting at next character in s1 */
s1++;
}
return(s1);
}
#endif
+403
View File
@@ -0,0 +1,403 @@
/* 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.
*/
#include "apr.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "apr_fnmatch.h"
#if 0
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#endif
#include "apr_want.h"
#include "apr_cstr.h"
APR_DECLARE(void) apr_cstr_split_append(apr_array_header_t *array,
const char *input,
const char *sep_chars,
int chop_whitespace,
apr_pool_t *pool)
{
char *pats;
char *p;
pats = apr_pstrdup(pool, input); /* strtok wants non-const data */
p = apr_cstr_tokenize(sep_chars, &pats);
while (p)
{
if (chop_whitespace)
{
while (apr_isspace(*p))
p++;
{
char *e = p + (strlen(p) - 1);
while ((e >= p) && (apr_isspace(*e)))
e--;
*(++e) = '\0';
}
}
if (p[0] != '\0')
APR_ARRAY_PUSH(array, const char *) = p;
p = apr_cstr_tokenize(sep_chars, &pats);
}
return;
}
APR_DECLARE(apr_array_header_t *) apr_cstr_split(const char *input,
const char *sep_chars,
int chop_whitespace,
apr_pool_t *pool)
{
apr_array_header_t *a = apr_array_make(pool, 5, sizeof(input));
apr_cstr_split_append(a, input, sep_chars, chop_whitespace, pool);
return a;
}
APR_DECLARE(int) apr_cstr_match_glob_list(const char *str,
const apr_array_header_t *list)
{
int i;
for (i = 0; i < list->nelts; i++)
{
const char *this_pattern = APR_ARRAY_IDX(list, i, char *);
if (apr_fnmatch(this_pattern, str, 0) == APR_SUCCESS)
return TRUE;
}
return FALSE;
}
APR_DECLARE(int) apr_cstr_match_list(const char *str,
const apr_array_header_t *list)
{
int i;
for (i = 0; i < list->nelts; i++)
{
const char *this_str = APR_ARRAY_IDX(list, i, char *);
if (strcmp(this_str, str) == 0)
return TRUE;
}
return FALSE;
}
APR_DECLARE(char *) apr_cstr_tokenize(const char *sep, char **str)
{
char *token;
char *next;
char csep;
/* check parameters */
if ((sep == NULL) || (str == NULL) || (*str == NULL))
return NULL;
/* let APR handle edge cases and multiple separators */
csep = *sep;
if (csep == '\0' || sep[1] != '\0')
return apr_strtok(NULL, sep, str);
/* skip characters in sep (will terminate at '\0') */
token = *str;
while (*token == csep)
++token;
if (!*token) /* no more tokens */
return NULL;
/* skip valid token characters to terminate token and
* prepare for the next call (will terminate at '\0)
*/
next = strchr(token, csep);
if (next == NULL)
{
*str = token + strlen(token);
}
else
{
*next = '\0';
*str = next + 1;
}
return token;
}
APR_DECLARE(int) apr_cstr_count_newlines(const char *msg)
{
int count = 0;
const char *p;
for (p = msg; *p; p++)
{
if (*p == '\n')
{
count++;
if (*(p + 1) == '\r')
p++;
}
else if (*p == '\r')
{
count++;
if (*(p + 1) == '\n')
p++;
}
}
return count;
}
#if 0 /* XXX: stringbuf logic is not present in APR */
APR_DECLARE(char *) apr_cstr_join(const apr_array_header_t *strings,
const char *separator,
apr_pool_t *pool)
{
svn_stringbuf_t *new_str = svn_stringbuf_create_empty(pool);
size_t sep_len = strlen(separator);
int i;
for (i = 0; i < strings->nelts; i++)
{
const char *string = APR_ARRAY_IDX(strings, i, const char *);
svn_stringbuf_appendbytes(new_str, string, strlen(string));
svn_stringbuf_appendbytes(new_str, separator, sep_len);
}
return new_str->data;
}
#endif
#if !APR_CHARSET_EBCDIC
/*
* Our own known-fast translation table for casecmp by character.
* Only ASCII alpha characters 41-5A are folded to 61-7A, other
* octets (such as extended latin alphabetics) are never case-folded.
* NOTE: Other than Alpha A-Z/a-z, each code point is unique!
*/
static const short ucharmap[] = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
#else /* APR_CHARSET_EBCDIC */
/*
* Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison,
* provides unique identity of every char value (strict ISO-646
* conformance, arbitrary election of an ISO-8859-1 ordering, and
* very arbitrary control code assignments into C1 to achieve
* identity and a reversible mapping of code points),
* then folding the equivalences of ASCII 41-5A into 61-7A,
* presenting comparison results in a somewhat ISO/IEC 10646
* (ASCII-like) order, depending on the EBCDIC code page in use.
*
* NOTE: Other than Alpha A-Z/a-z, each code point is unique!
*/
static const short ucharmap[] = {
0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5,
0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF,
0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5,
0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF,
0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE,
0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC,
0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7,
0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F
};
#endif
APR_DECLARE(int) apr_cstr_casecmp(const char *s1, const char *s2)
{
const unsigned char *str1 = (const unsigned char *)s1;
const unsigned char *str2 = (const unsigned char *)s2;
for (;;)
{
const int c1 = (int)(*str1);
const int c2 = (int)(*str2);
const int cmp = ucharmap[c1] - ucharmap[c2];
/* Not necessary to test for !c2, this is caught by cmp */
if (cmp || !c1)
return cmp;
str1++;
str2++;
}
}
APR_DECLARE(int) apr_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
{
const unsigned char *str1 = (const unsigned char *)s1;
const unsigned char *str2 = (const unsigned char *)s2;
while (n--)
{
const int c1 = (int)(*str1);
const int c2 = (int)(*str2);
const int cmp = ucharmap[c1] - ucharmap[c2];
/* Not necessary to test for !c2, this is caught by cmp */
if (cmp || !c1)
return cmp;
str1++;
str2++;
}
return 0;
}
APR_DECLARE(apr_status_t) apr_cstr_strtoui64(apr_uint64_t *n, const char *str,
apr_uint64_t minval, apr_uint64_t maxval,
int base)
{
apr_int64_t val;
char *endptr;
/* We assume errno is thread-safe. */
errno = 0; /* APR-0.9 doesn't always set errno */
/* ### We're throwing away half the number range here.
* ### APR needs a apr_strtoui64() function. */
val = apr_strtoi64(str, &endptr, base);
if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
return APR_EINVAL;
if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
val < 0 || (apr_uint64_t)val < minval || (apr_uint64_t)val > maxval)
return APR_ERANGE;
*n = val;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_cstr_atoui64(apr_uint64_t *n, const char *str)
{
return apr_cstr_strtoui64(n, str, 0, APR_UINT64_MAX, 10);
}
APR_DECLARE(apr_status_t) apr_cstr_atoui(unsigned int *n, const char *str)
{
apr_uint64_t val;
apr_status_t rv = apr_cstr_strtoui64(&val, str, 0, APR_UINT32_MAX, 10);
if (rv == APR_SUCCESS)
*n = (unsigned int)val;
return rv;
}
APR_DECLARE(apr_status_t) apr_cstr_strtoi64(apr_int64_t *n, const char *str,
apr_int64_t minval, apr_int64_t maxval,
int base)
{
apr_int64_t val;
char *endptr;
/* We assume errno is thread-safe. */
errno = 0; /* APR-0.9 doesn't always set errno */
val = apr_strtoi64(str, &endptr, base);
if (errno == EINVAL || endptr == str || str[0] == '\0' || *endptr != '\0')
return APR_EINVAL;
if ((errno == ERANGE && (val == APR_INT64_MIN || val == APR_INT64_MAX)) ||
val < minval || val > maxval)
return APR_ERANGE;
*n = val;
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_cstr_atoi64(apr_int64_t *n, const char *str)
{
return apr_cstr_strtoi64(n, str, APR_INT64_MIN, APR_INT64_MAX, 10);
}
APR_DECLARE(apr_status_t) apr_cstr_atoi(int *n, const char *str)
{
apr_int64_t val;
apr_status_t rv;
rv = apr_cstr_strtoi64(&val, str, APR_INT32_MIN, APR_INT32_MAX, 10);
if (rv == APR_SUCCESS)
*n = (int)val;
return rv;
}
APR_DECLARE(const char *) apr_cstr_skip_prefix(const char *str,
const char *prefix)
{
apr_size_t len = strlen(prefix);
if (strncmp(str, prefix, len) == 0)
{
return str + len;
}
else
{
return NULL;
}
}
+482
View File
@@ -0,0 +1,482 @@
/* 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.
*/
/* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008
* as described in;
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html
*
* Filename pattern matches defined in section 2.13, "Pattern Matching Notation"
* from chapter 2. "Shell Command Language"
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13
* where; 1. A bracket expression starting with an unquoted <circumflex> '^'
* character CONTINUES to specify a non-matching list; 2. an explicit <period> '.'
* in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading
* <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce
* a valid bracket expression is treated as an ordinary character; 4. a differing
* number of consecutive slashes within pattern and string will NOT match;
* 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character.
*
* Bracket expansion defined in section 9.3.5, "RE Bracket Expression",
* from chapter 9, "Regular Expressions"
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05
* with no support for collating symbols, equivalence class expressions or
* character class expressions. A partial range expression with a leading
* hyphen following a valid range expression will match only the ordinary
* <hyphen> and the ending character (e.g. "[a-m-z]" will match characters
* 'a' through 'm', a <hyphen> '-', or a 'z').
*
* NOTE: Only POSIX/C single byte locales are correctly supported at this time.
* Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results,
* particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and
* nonalpha characters within a range.
*
* XXX comments below indicate porting required for multi-byte character sets
* and non-POSIX locale collation orders; requires mbr* APIs to track shift
* state of pattern and string (rewinding pattern and string repeatedly).
*
* Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g.
* UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate
* path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS.
*/
#include "apr_file_info.h"
#include "apr_fnmatch.h"
#include "apr_tables.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include <string.h>
#if APR_HAVE_CTYPE_H
# include <ctype.h>
#endif
/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled.
* EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over,
* however the "\/" sequence is advanced to '/'.
*
* Both pattern and string are **char to support pointer increment of arbitrary
* multibyte characters for the given locale, in a later iteration of this code
*/
static APR_INLINE int fnmatch_ch(const char **pattern, const char **string, int flags)
{
const char * const mismatch = *pattern;
const int nocase = !!(flags & APR_FNM_CASE_BLIND);
const int escape = !(flags & APR_FNM_NOESCAPE);
const int slash = !!(flags & APR_FNM_PATHNAME);
int result = APR_FNM_NOMATCH;
const char *startch;
int negate;
if (**pattern == '[')
{
++*pattern;
/* Handle negation, either leading ! or ^ operators (never both) */
negate = ((**pattern == '!') || (**pattern == '^'));
if (negate)
++*pattern;
/* ']' is an ordinary character at the start of the range pattern */
if (**pattern == ']')
goto leadingclosebrace;
while (**pattern)
{
if (**pattern == ']') {
++*pattern;
/* XXX: Fix for MBCS character width */
++*string;
return (result ^ negate);
}
if (escape && (**pattern == '\\')) {
++*pattern;
/* Patterns must be terminated with ']', not EOS */
if (!**pattern)
break;
}
/* Patterns must be terminated with ']' not '/' */
if (slash && (**pattern == '/'))
break;
leadingclosebrace:
/* Look at only well-formed range patterns;
* "x-]" is not allowed unless escaped ("x-\]")
* XXX: Fix for locale/MBCS character width
*/
if (((*pattern)[1] == '-') && ((*pattern)[2] != ']'))
{
startch = *pattern;
*pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
/* NOT a properly balanced [expr] pattern, EOS terminated
* or ranges containing a slash in FNM_PATHNAME mode pattern
* fall out to to the rewind and test '[' literal code path
*/
if (!**pattern || (slash && (**pattern == '/')))
break;
/* XXX: handle locale/MBCS comparison, advance by MBCS char width */
if ((**string >= *startch) && (**string <= **pattern))
result = 0;
else if (nocase && (isupper(**string) || isupper(*startch)
|| isupper(**pattern))
&& (tolower(**string) >= tolower(*startch))
&& (tolower(**string) <= tolower(**pattern)))
result = 0;
++*pattern;
continue;
}
/* XXX: handle locale/MBCS comparison, advance by MBCS char width */
if ((**string == **pattern))
result = 0;
else if (nocase && (isupper(**string) || isupper(**pattern))
&& (tolower(**string) == tolower(**pattern)))
result = 0;
++*pattern;
}
/* NOT a properly balanced [expr] pattern; Rewind
* and reset result to test '[' literal
*/
*pattern = mismatch;
result = APR_FNM_NOMATCH;
}
else if (**pattern == '?') {
/* Optimize '?' match before unescaping **pattern */
if (!**string || (slash && (**string == '/')))
return APR_FNM_NOMATCH;
result = 0;
goto fnmatch_ch_success;
}
else if (escape && (**pattern == '\\') && (*pattern)[1]) {
++*pattern;
}
/* XXX: handle locale/MBCS comparison, advance by the MBCS char width */
if (**string == **pattern)
result = 0;
else if (nocase && (isupper(**string) || isupper(**pattern))
&& (tolower(**string) == tolower(**pattern)))
result = 0;
/* Refuse to advance over trailing slash or nulls
*/
if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/'))))
return result;
fnmatch_ch_success:
++*pattern;
++*string;
return result;
}
APR_DECLARE(int) apr_fnmatch(const char *pattern, const char *string, int flags)
{
static const char dummystring[2] = {' ', 0};
const int escape = !(flags & APR_FNM_NOESCAPE);
const int slash = !!(flags & APR_FNM_PATHNAME);
const char *strendseg;
const char *dummyptr;
const char *matchptr;
int wild;
/* For '*' wild processing only; surpress 'used before initialization'
* warnings with dummy initialization values;
*/
const char *strstartseg = NULL;
const char *mismatch = NULL;
int matchlen = 0;
if (*pattern == '*')
goto firstsegment;
while (*pattern && *string)
{
/* Pre-decode "\/" which has no special significance, and
* match balanced slashes, starting a new segment pattern
*/
if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
++pattern;
if (slash && (*pattern == '/') && (*string == '/')) {
++pattern;
++string;
}
firstsegment:
/* At the beginning of each segment, validate leading period behavior.
*/
if ((flags & APR_FNM_PERIOD) && (*string == '.'))
{
if (*pattern == '.')
++pattern;
else if (escape && (*pattern == '\\') && (pattern[1] == '.'))
pattern += 2;
else
return APR_FNM_NOMATCH;
++string;
}
/* Determine the end of string segment
*
* Presumes '/' character is unique, not composite in any MBCS encoding
*/
if (slash) {
strendseg = strchr(string, '/');
if (!strendseg)
strendseg = strchr(string, '\0');
}
else {
strendseg = strchr(string, '\0');
}
/* Allow pattern '*' to be consumed even with no remaining string to match
*/
while (*pattern)
{
if ((string > strendseg)
|| ((string == strendseg) && (*pattern != '*')))
break;
if (slash && ((*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/'))))
break;
/* Reduce groups of '*' and '?' to n '?' matches
* followed by one '*' test for simplicity
*/
for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern)
{
if (*pattern == '*') {
wild = 1;
}
else if (string < strendseg) { /* && (*pattern == '?') */
/* XXX: Advance 1 char for MBCS locale */
++string;
}
else { /* (string >= strendseg) && (*pattern == '?') */
return APR_FNM_NOMATCH;
}
}
if (wild)
{
strstartseg = string;
mismatch = pattern;
/* Count fixed (non '*') char matches remaining in pattern
* excluding '/' (or "\/") and '*'
*/
for (matchptr = pattern, matchlen = 0; 1; ++matchlen)
{
if ((*matchptr == '\0')
|| (slash && ((*matchptr == '/')
|| (escape && (*matchptr == '\\')
&& (matchptr[1] == '/')))))
{
/* Compare precisely this many trailing string chars,
* the resulting match needs no wildcard loop
*/
/* XXX: Adjust for MBCS */
if (string + matchlen > strendseg)
return APR_FNM_NOMATCH;
string = strendseg - matchlen;
wild = 0;
break;
}
if (*matchptr == '*')
{
/* Ensure at least this many trailing string chars remain
* for the first comparison
*/
/* XXX: Adjust for MBCS */
if (string + matchlen > strendseg)
return APR_FNM_NOMATCH;
/* Begin first wild comparison at the current position */
break;
}
/* Skip forward in pattern by a single character match
* Use a dummy fnmatch_ch() test to count one "[range]" escape
*/
/* XXX: Adjust for MBCS */
if (escape && (*matchptr == '\\') && matchptr[1]) {
matchptr += 2;
}
else if (*matchptr == '[') {
dummyptr = dummystring;
fnmatch_ch(&matchptr, &dummyptr, flags);
}
else {
++matchptr;
}
}
}
/* Incrementally match string against the pattern
*/
while (*pattern && (string < strendseg))
{
/* Success; begin a new wild pattern search
*/
if (*pattern == '*')
break;
if (slash && ((*string == '/')
|| (*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/'))))
break;
/* Compare ch's (the pattern is advanced over "\/" to the '/',
* but slashes will mismatch, and are not consumed)
*/
if (!fnmatch_ch(&pattern, &string, flags))
continue;
/* Failed to match, loop against next char offset of string segment
* until not enough string chars remain to match the fixed pattern
*/
if (wild) {
/* XXX: Advance 1 char for MBCS locale */
string = ++strstartseg;
if (string + matchlen > strendseg)
return APR_FNM_NOMATCH;
pattern = mismatch;
continue;
}
else
return APR_FNM_NOMATCH;
}
}
if (*string && !(slash && (*string == '/')))
return APR_FNM_NOMATCH;
if (*pattern && !(slash && ((*pattern == '/')
|| (escape && (*pattern == '\\')
&& (pattern[1] == '/')))))
return APR_FNM_NOMATCH;
}
/* Where both pattern and string are at EOS, declare success
*/
if (!*string && !*pattern)
return 0;
/* pattern didn't match to the end of string */
return APR_FNM_NOMATCH;
}
/* This function is an Apache addition
* return non-zero if pattern has any glob chars in it
* @bug Function does not distinguish for FNM_PATHNAME mode, which renders
* a false positive for test[/]this (which is not a range, but
* seperate test[ and ]this segments and no glob.)
* @bug Function does not distinguish for non-FNM_ESCAPE mode.
* @bug Function does not parse []] correctly
* Solution may be to use fnmatch_ch() to walk the patterns?
*/
APR_DECLARE(int) apr_fnmatch_test(const char *pattern)
{
int nesting;
nesting = 0;
while (*pattern) {
switch (*pattern) {
case '?':
case '*':
return 1;
case '\\':
if (*++pattern == '\0') {
return 0;
}
break;
case '[': /* '[' is only a glob if it has a matching ']' */
++nesting;
break;
case ']':
if (nesting) {
return 1;
}
break;
}
++pattern; }
return 0;
}
/* Find all files matching the specified pattern */
APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern,
apr_array_header_t **result,
apr_pool_t *p)
{
apr_dir_t *dir;
apr_finfo_t finfo;
apr_status_t rv;
char *path;
/* XXX So, this is kind of bogus. Basically, I need to strip any leading
* directories off the pattern, but there is no portable way to do that.
* So, for now we just find the last occurance of '/' and if that doesn't
* return anything, then we look for '\'. This means that we could
* screw up on unix if the pattern is something like "foo\.*" That '\'
* isn't a directory delimiter, it is a part of the filename. To fix this,
* we really need apr_filepath_basename, which will be coming as soon as
* I get to it. rbb
*/
char *idx = strrchr(pattern, '/');
if (idx == NULL) {
idx = strrchr(pattern, '\\');
}
if (idx == NULL) {
path = ".";
}
else {
path = apr_pstrmemdup(p, pattern, idx - pattern);
pattern = idx + 1;
}
*result = apr_array_make(p, 0, sizeof(char *));
rv = apr_dir_open(&dir, path, p);
if (rv != APR_SUCCESS) {
return rv;
}
while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS) {
if (apr_fnmatch(pattern, finfo.name, 0) == APR_SUCCESS) {
*(const char **)apr_array_push(*result) = apr_pstrdup(p, finfo.name);
}
}
apr_dir_close(dir);
return APR_SUCCESS;
}
File diff suppressed because it is too large Load Diff
+467
View File
@@ -0,0 +1,467 @@
/* 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.
*/
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_general.h"
#include "apr_private.h"
#include "apr_lib.h"
#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#include "apr_want.h"
#ifdef HAVE_STDDEF_H
#include <stddef.h> /* NULL */
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h> /* strtol and strtoll */
#endif
/** this is used to cache lengths in apr_pstrcat */
#define MAX_SAVED_LENGTHS 6
APR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s)
{
char *res;
apr_size_t len;
if (s == NULL) {
return NULL;
}
len = strlen(s) + 1;
res = apr_pmemdup(a, s, len);
return res;
}
APR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n)
{
char *res;
const char *end;
if (s == NULL) {
return NULL;
}
end = memchr(s, '\0', n);
if (end != NULL)
n = end - s;
res = apr_palloc(a, n + 1);
memcpy(res, s, n);
res[n] = '\0';
return res;
}
APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n)
{
char *res;
if (s == NULL) {
return NULL;
}
res = apr_palloc(a, n + 1);
memcpy(res, s, n);
res[n] = '\0';
return res;
}
APR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n)
{
void *res;
if (m == NULL)
return NULL;
res = apr_palloc(a, n);
memcpy(res, m, n);
return res;
}
APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...)
{
char *cp, *argp, *res;
apr_size_t saved_lengths[MAX_SAVED_LENGTHS];
int nargs = 0;
/* Pass one --- find length of required string */
apr_size_t len = 0;
va_list adummy;
va_start(adummy, a);
while ((cp = va_arg(adummy, char *)) != NULL) {
apr_size_t cplen = strlen(cp);
if (nargs < MAX_SAVED_LENGTHS) {
saved_lengths[nargs++] = cplen;
}
len += cplen;
}
va_end(adummy);
/* Allocate the required string */
res = (char *) apr_palloc(a, len + 1);
cp = res;
/* Pass two --- copy the argument strings into the result space */
va_start(adummy, a);
nargs = 0;
while ((argp = va_arg(adummy, char *)) != NULL) {
if (nargs < MAX_SAVED_LENGTHS) {
len = saved_lengths[nargs++];
}
else {
len = strlen(argp);
}
memcpy(cp, argp, len);
cp += len;
}
va_end(adummy);
/* Return the result string */
*cp = '\0';
return res;
}
APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec,
apr_size_t nvec, apr_size_t *nbytes)
{
apr_size_t i;
apr_size_t len;
const struct iovec *src;
char *res;
char *dst;
/* Pass one --- find length of required string */
len = 0;
src = vec;
for (i = nvec; i; i--) {
len += src->iov_len;
src++;
}
if (nbytes) {
*nbytes = len;
}
/* Allocate the required string */
res = (char *) apr_palloc(a, len + 1);
/* Pass two --- copy the argument strings into the result space */
src = vec;
dst = res;
for (i = nvec; i; i--) {
memcpy(dst, src->iov_base, src->iov_len);
dst += src->iov_len;
src++;
}
/* Return the result string */
*dst = '\0';
return res;
}
#if (!APR_HAVE_MEMCHR)
void *memchr(const void *s, int c, size_t n)
{
const char *cp;
for (cp = s; n > 0; n--, cp++) {
if (*cp == c)
return (char *) cp; /* Casting away the const here */
}
return NULL;
}
#endif
#ifndef INT64_MAX
#define INT64_MAX APR_INT64_C(0x7fffffffffffffff)
#endif
#ifndef INT64_MIN
#define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1))
#endif
APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr,
char **endptr, int base)
{
errno = 0;
*offset = APR_OFF_T_STRFN(nptr, endptr, base);
return APR_FROM_OS_ERROR(errno);
}
APR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base)
{
#ifdef APR_INT64_STRFN
errno = 0;
return APR_INT64_STRFN(nptr, endptr, base);
#else
const char *s;
apr_int64_t acc;
apr_int64_t val;
int neg, any;
char c;
errno = 0;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
s = nptr;
do {
c = *s++;
} while (apr_isspace(c));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36) {
errno = EINVAL;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return acc;
}
/* The classic bsd implementation requires div/mod operators
* to compute a cutoff. Benchmarking proves that is very, very
* evil to some 32 bit processors. Instead, look for underflow
* in both the mult and add/sub operation. Unlike the bsd impl,
* we also work strictly in a signed int64 word as we haven't
* implemented the unsigned type in win32.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
val = 0;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
#if (('Z' - 'A') == 25)
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
#elif APR_CHARSET_EBCDIC
else if (c >= 'A' && c <= 'I')
c -= 'A' - 10;
else if (c >= 'J' && c <= 'R')
c -= 'J' - 19;
else if (c >= 'S' && c <= 'Z')
c -= 'S' - 28;
else if (c >= 'a' && c <= 'i')
c -= 'a' - 10;
else if (c >= 'j' && c <= 'r')
c -= 'j' - 19;
else if (c >= 's' && c <= 'z')
c -= 'z' - 28;
#else
#error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported"
#endif
else
break;
if (c >= base)
break;
val *= base;
if ( (any < 0) /* already noted an over/under flow - short circuit */
|| (neg && (val > acc || (val -= c) > acc)) /* underflow */
|| (!neg && (val < acc || (val += c) < acc))) { /* overflow */
any = -1; /* once noted, over/underflows never go away */
#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR
break;
#endif
} else {
acc = val;
any = 1;
}
}
if (any < 0) {
acc = neg ? INT64_MIN : INT64_MAX;
errno = ERANGE;
} else if (!any) {
errno = EINVAL;
}
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
#endif
}
APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf)
{
return apr_strtoi64(buf, NULL, 10);
}
APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n)
{
const int BUFFER_SIZE = sizeof(int) * 3 + 2;
char *buf = apr_palloc(p, BUFFER_SIZE);
char *start = buf + BUFFER_SIZE - 1;
int negative;
if (n < 0) {
negative = 1;
n = -n;
}
else {
negative = 0;
}
*start = 0;
do {
*--start = '0' + (n % 10);
n /= 10;
} while (n);
if (negative) {
*--start = '-';
}
return start;
}
APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n)
{
const int BUFFER_SIZE = sizeof(long) * 3 + 2;
char *buf = apr_palloc(p, BUFFER_SIZE);
char *start = buf + BUFFER_SIZE - 1;
int negative;
if (n < 0) {
negative = 1;
n = -n;
}
else {
negative = 0;
}
*start = 0;
do {
*--start = (char)('0' + (n % 10));
n /= 10;
} while (n);
if (negative) {
*--start = '-';
}
return start;
}
APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n)
{
const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2;
char *buf = apr_palloc(p, BUFFER_SIZE);
char *start = buf + BUFFER_SIZE - 1;
int negative;
if (n < 0) {
negative = 1;
n = -n;
}
else {
negative = 0;
}
*start = 0;
do {
*--start = '0' + (char)(n % 10);
n /= 10;
} while (n);
if (negative) {
*--start = '-';
}
return start;
}
APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf)
{
const char ord[] = "KMGTPE";
const char *o = ord;
int remain;
if (size < 0) {
return strcpy(buf, " - ");
}
if (size < 973) {
if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0)
return strcpy(buf, "****");
return buf;
}
do {
remain = (int)(size & 1023);
size >>= 10;
if (size >= 973) {
++o;
continue;
}
if (size < 9 || (size == 9 && remain < 973)) {
if ((remain = ((remain * 5) + 256) / 512) >= 10)
++size, remain = 0;
if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0)
return strcpy(buf, "****");
return buf;
}
if (remain >= 512)
++size;
if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0)
return strcpy(buf, "****");
return buf;
} while (1);
}
+149
View File
@@ -0,0 +1,149 @@
/* -*- mode: c; c-file-style: "k&r" -*-
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <ctype.h>
#include <string.h>
#include "apr_strings.h"
#include "apr_lib.h" /* for apr_is*() */
#if defined(__GNUC__)
# define UNUSED __attribute__((__unused__))
#else
# define UNUSED
#endif
/* based on "strnatcmp.c,v 1.6 2000/04/20 07:30:11 mbp Exp $" */
static int
compare_right(char const *a, char const *b)
{
int bias = 0;
/* The longest run of digits wins. That aside, the greatest
value wins, but we can't know that it will until we've scanned
both numbers to know that they have the same magnitude, so we
remember it in BIAS. */
for (;; a++, b++) {
if (!apr_isdigit(*a) && !apr_isdigit(*b))
break;
else if (!apr_isdigit(*a))
return -1;
else if (!apr_isdigit(*b))
return +1;
else if (*a < *b) {
if (!bias)
bias = -1;
} else if (*a > *b) {
if (!bias)
bias = +1;
} else if (!*a && !*b)
break;
}
return bias;
}
static int
compare_left(char const *a, char const *b)
{
/* Compare two left-aligned numbers: the first to have a
different value wins. */
for (;; a++, b++) {
if (!apr_isdigit(*a) && !apr_isdigit(*b))
break;
else if (!apr_isdigit(*a))
return -1;
else if (!apr_isdigit(*b))
return +1;
else if (*a < *b)
return -1;
else if (*a > *b)
return +1;
}
return 0;
}
static int strnatcmp0(char const *a, char const *b, int fold_case)
{
int ai, bi;
char ca, cb;
int fractional, result;
ai = bi = 0;
while (1) {
ca = a[ai]; cb = b[bi];
/* skip over leading spaces or zeros */
while (apr_isspace(ca))
ca = a[++ai];
while (apr_isspace(cb))
cb = b[++bi];
/* process run of digits */
if (apr_isdigit(ca) && apr_isdigit(cb)) {
fractional = (ca == '0' || cb == '0');
if (fractional) {
if ((result = compare_left(a+ai, b+bi)) != 0)
return result;
} else {
if ((result = compare_right(a+ai, b+bi)) != 0)
return result;
}
}
if (!ca && !cb) {
/* The strings compare the same. Perhaps the caller
will want to call strcmp to break the tie. */
return 0;
}
if (fold_case) {
ca = apr_toupper(ca);
cb = apr_toupper(cb);
}
if (ca < cb)
return -1;
else if (ca > cb)
return +1;
++ai; ++bi;
}
}
APR_DECLARE(int) apr_strnatcmp(char const *a, char const *b)
{
return strnatcmp0(a, b, 0);
}
/* Compare, recognizing numeric string and ignoring case. */
APR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b)
{
return strnatcmp0(a, b, 1);
}
+56
View File
@@ -0,0 +1,56 @@
/* 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.
*/
#ifdef HAVE_STDDEF_H
#include <stddef.h> /* for NULL */
#endif
#include "apr.h"
#include "apr_strings.h"
#define APR_WANT_STRFUNC /* for strchr() */
#include "apr_want.h"
APR_DECLARE(char *) apr_strtok(char *str, const char *sep, char **last)
{
char *token;
if (!str) /* subsequent call */
str = *last; /* start where we left off */
/* skip characters in sep (will terminate at '\0') */
while (*str && strchr(sep, *str))
++str;
if (!*str) /* no more tokens */
return NULL;
token = str;
/* skip valid token characters to terminate token and
* prepare for the next call (will terminate at '\0)
*/
*last = token + 1;
while (**last && !strchr(sep, **last))
++*last;
if (**last) {
**last = '\0';
++*last;
}
return token;
}