feat:replace boost library with C++11 std library
This commit is contained in:
+315
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
+1408
File diff suppressed because it is too large
Load Diff
+467
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user