diff options
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/mpr/mprString.c')
-rw-r--r-- | source4/lib/appweb/ejs-2.0/mpr/mprString.c | 733 |
1 files changed, 733 insertions, 0 deletions
diff --git a/source4/lib/appweb/ejs-2.0/mpr/mprString.c b/source4/lib/appweb/ejs-2.0/mpr/mprString.c new file mode 100644 index 0000000000..d39fc8b746 --- /dev/null +++ b/source4/lib/appweb/ejs-2.0/mpr/mprString.c @@ -0,0 +1,733 @@ +/** + * @file mprString.c + * @brief String routines safe for embedded programming + * @overview This module provides safe replacements for the standard + * string library. + * @remarks Most routines in this file are not thread-safe. It is the callers + * responsibility to perform all thread synchronization. + */ + +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. + * + * This software is distributed under commercial and open source licenses. + * You may use the GPL open source license described below or you may acquire + * a commercial license from Mbedthis Software. You agree to be fully bound + * by the terms of either license. Consult the LICENSE.TXT distributed with + * this software for full details. + * + * This software is open source; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See the GNU General Public License for more + * details at: http://www.mbedthis.com/downloads/gplLicense.html + * + * This program is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * This GPL license does NOT permit incorporating this software into + * proprietary programs. If you are unable to comply with the GPL, you must + * acquire a commercial license to use this software. Commercial licenses + * for this software and support services are available from Mbedthis + * Software at http://www.mbedthis.com + * + * @end + */ + +#include "mpr.h" + +/********************************** Includes **********************************/ +/* + * We need to use the underlying str(cpy) routines to implement our safe + * alternatives + */ +#if !DOXYGEN +#define UNSAFE_FUNCTIONS_OK 1 +#endif + +/******************************************************************************/ +/**************************** Safe String Handling ****************************/ +/******************************************************************************/ + +int mprStrcpy(char *dest, int destMax, const char *src) +{ + int len; + + mprAssert(dest); + mprAssert(destMax >= 0); + mprAssert(src); + + len = strlen(src); + if (destMax > 0 && len >= destMax && len > 0) { + return MPR_ERR_WONT_FIT; + } + if (len > 0) { + memcpy(dest, src, len); + dest[len] = '\0'; + } else { + *dest = '\0'; + len = 0; + } + return len; +} + +/******************************************************************************/ + +int mprAllocStrcpy(MPR_LOC_DEC(ctx, loc), char **dest, int destMax, + const char *src) +{ + int len; + + mprAssert(dest); + mprAssert(destMax >= 0); + mprAssert(src); + + len = strlen(src); + if (destMax > 0 && len >= destMax) { + mprAssert(0); + return MPR_ERR_WONT_FIT; + } + if (len > 0) { + *dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), len); + memcpy(*dest, src, len); + (*dest)[len] = '\0'; + } else { + *dest = (char*) mprAlloc(ctx, 1); + *dest = '\0'; + len = 0; + } + return len; +} + +/******************************************************************************/ + +int mprMemcpy(char *dest, int destMax, const char *src, int nbytes) +{ + mprAssert(dest); + mprAssert(destMax <= 0 || destMax >= nbytes); + mprAssert(src); + mprAssert(nbytes >= 0); + + if (destMax > 0 && nbytes > destMax) { + mprAssert(0); + return MPR_ERR_WONT_FIT; + } + if (nbytes > 0) { + memcpy(dest, src, nbytes); + return nbytes; + } else { + return 0; + } +} + +/******************************************************************************/ + +int mprAllocMemcpy(MPR_LOC_DEC(ctx, loc), char **dest, int destMax, + const void *src, int nbytes) +{ + mprAssert(dest); + mprAssert(src); + mprAssert(nbytes > 0); + mprAssert(destMax <= 0 || destMax >= nbytes); + + if (destMax > 0 && nbytes > destMax) { + mprAssert(0); + return MPR_ERR_WONT_FIT; + } + if (nbytes > 0) { + *dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx,loc), nbytes); + if (*dest == 0) { + return MPR_ERR_MEMORY; + } + memcpy(*dest, src, nbytes); + } else { + *dest = (char*) mprAlloc(ctx, 1); + } + return nbytes; +} + +/******************************************************************************/ + +static int mprCoreStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax, + int existingLen, const char *delim, const char *src, va_list args) +{ + va_list ap; + char *dest, *str, *dp; + int sepLen, addBytes, required; + + mprAssert(destp); + mprAssert(destMax >= 0); + mprAssert(src); + + dest = *destp; + sepLen = (delim) ? strlen(delim) : 0; + +#ifdef __va_copy + __va_copy(ap, args); +#else + ap = args; +#endif + addBytes = 0; + if (existingLen > 0) { + addBytes += sepLen; + } + str = (char*) src; + + while (str) { + addBytes += strlen(str); + str = va_arg(ap, char*); + if (str) { + addBytes += sepLen; + } + } + + required = existingLen + addBytes + 1; + if (destMax > 0 && required >= destMax) { + mprAssert(0); + return MPR_ERR_WONT_FIT; + } + + if (ctx != 0) { + if (dest == 0) { + dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), required); + } else { + dest = (char*) mprReallocBlock(MPR_LOC_PASS(ctx, loc), dest, + required); + } + } else { + dest = (char*) *destp; + } + + dp = &dest[existingLen]; + if (delim && existingLen > 0) { + strcpy(dp, delim); + dp += sepLen; + } + + if (addBytes > 0) { +#ifdef __va_copy + __va_copy(ap, args); +#else + ap = args; +#endif + str = (char*) src; + while (str) { + strcpy(dp, str); + dp += strlen(str); + str = va_arg(ap, char*); + if (delim && str) { + strcpy(dp, delim); + dp += sepLen; + } + } + } else if (dest == 0) { + dest = (char*) mprAlloc(ctx, 1); + } + *dp = '\0'; + + *destp = dest; + mprAssert(dp < &dest[required]); + return required - 1; +} + +/***************************************************************************** + Note that this VARARGS function must be NULL (not 0, this must be a + pointer) terminated +*/ +int mprStrcat(char *dest, int destMax, const char *delim, const char *src, ...) +{ + va_list ap; + int rc; + + mprAssert(dest); + mprAssert(src); + + va_start(ap, src); + rc = mprCoreStrcat(MPR_LOC_ARGS(0), &dest, destMax, strlen(dest), + delim, src, ap); + va_end(ap); + return rc; +} + +/***************************************************************************** + Note that this VARARGS function must be NULL (not 0, this must be a + pointer) terminated +*/ +int mprAllocStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax, + const char *delim, const char *src, ...) +{ + va_list ap; + int rc; + + mprAssert(destp); + mprAssert(src); + + *destp = 0; + va_start(ap, src); + rc = mprCoreStrcat(MPR_LOC_PASS(ctx, loc), destp, destMax, 0, delim, + src, ap); + va_end(ap); + return rc; +} + +/***************************************************************************** + Note that this VARARGS function must be NULL (not 0, this must be a + pointer) terminated +*/ +int mprReallocStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax, + int existingLen, const char *delim, const char *src,...) +{ + va_list ap; + int rc; + + va_start(ap, src); + rc = mprCoreStrcat(MPR_LOC_PASS(ctx, loc), destp, destMax, existingLen, + delim, src, ap); + va_end(ap); + return rc; +} + +/******************************************************************************/ + +int mprStrlen(const char *src, int max) +{ + int len; + + len = strlen(src); + if (len >= max) { + mprAssert(0); + return MPR_ERR_WONT_FIT; + } + return len; +} + +/******************************************************************************/ + +char *mprStrTrim(char *str, const char *set) +{ + int len, i; + + if (str == 0 || set == 0) { + return str; + } + + i = strspn(str, set); + str += i; + + len = strlen(str); + while (strspn(&str[len - 1], set) > 0) { + str[len - 1] = '\0'; + len--; + } + return str; +} + +/******************************************************************************/ +/* + * Map a string to lower case (overwrites original string) + */ + +char *mprStrLower(char *str) +{ + char *cp; + + mprAssert(str); + + if (str == 0) { + return 0; + } + + for (cp = str; *cp; cp++) { + if (isupper(*cp)) { + *cp = (char) tolower(*cp); + } + } + return str; +} + +/******************************************************************************/ +/* + * Map a string to upper case (overwrites buffer) + */ + +char *mprStrUpper(char *str) +{ + char *cp; + + mprAssert(str); + if (str == 0) { + return 0; + } + + for (cp = str; *cp; cp++) { + if (islower(*cp)) { + *cp = (char) toupper(*cp); + } + } + return str; +} + +/******************************************************************************/ +/* + * Case insensitive string comparison. Stop at the end of str1. + */ + +int mprStrcmpAnyCase(const char *str1, const char *str2) +{ + int rc; + + if (str1 == 0 || str2 == 0) { + return -1; + } + if (str1 == str2) { + return 0; + } + + for (rc = 0; *str1 && rc == 0; str1++, str2++) { + rc = tolower(*str1) - tolower(*str2); + } + if (*str2) { + return -1; + } + return rc; +} + +/******************************************************************************/ +/* + * Case insensitive string comparison. Limited by length + */ + +int mprStrcmpAnyCaseCount(const char *str1, const char *str2, int len) +{ + int rc; + + if (str1 == 0 || str2 == 0) { + return -1; + } + if (str1 == str2) { + return 0; + } + + for (rc = 0; len-- > 0 && *str1 && rc == 0; str1++, str2++) { + rc = tolower(*str1) - tolower(*str2); + } + return rc; +} + +/******************************************************************************/ +/* + * Return the last portion of a pathname + */ + +const char *mprGetBaseName(const char *name) +{ + char *cp; + + cp = strrchr(name, '/'); + + if (cp == 0) { + cp = strrchr(name, '\\'); + if (cp == 0) { + return name; + } + } + if (cp == name) { + if (cp[1] == '\0') { + return name; + } + } else { + if (cp[1] == '\0') { + return ""; + } + } + return &cp[1]; +} + +/******************************************************************************/ +/* + * Return the directory portion of a pathname into the users buffer. + */ + +char *mprGetDirName(char *buf, int bufsize, const char *path) +{ + char *cp; + int dlen; + + mprAssert(path); + mprAssert(buf); + mprAssert(bufsize > 0); + + cp = strrchr(path, '/'); + if (cp == 0) { +#if WIN + cp = strrchr(path, '\\'); + if (cp == 0) +#endif + { + buf[0] = '\0'; + return buf; + } + } + + if (cp == path && cp[1] == '\0') { + strcpy(buf, "."); + return buf; + } + + dlen = cp - path; + if (dlen < bufsize) { + if (dlen == 0) { + dlen++; + } + mprMemcpy(buf, bufsize, path, dlen); + buf[dlen] = '\0'; + return buf; + } + return 0; +} + +/******************************************************************************/ +/* + * Thread-safe wrapping of strtok. Note "str" is modifed as per strtok() + */ + +char *mprStrTok(char *str, const char *delim, char **last) +{ + char *start, *end; + int i; + + start = str ? str : *last; + + if (start == 0) { + return 0; + } + + i = strspn(start, delim); + start += i; + if (*start == '\0') { + *last = 0; + return 0; + } + end = strpbrk(start, delim); + if (end) { + *end++ = '\0'; + i = strspn(end, delim); + end += i; + } + *last = end; + return start; +} + +/******************************************************************************/ +/* + * Split the buffer into word tokens + */ + +char *mprGetWordTok(char *buf, int bufsize, const char *str, const char *delim, + const char **tok) +{ + const char *start, *end; + int i, len; + + start = str ? str : *tok; + + if (start == 0) { + return 0; + } + + i = strspn(start, delim); + start += i; + if (*start =='\0') { + *tok = 0; + return 0; + } + end = strpbrk(start, delim); + if (end) { + len = min(end - start, bufsize - 1); + mprMemcpy(buf, bufsize, start, len); + buf[len] = '\0'; + } else { + if (mprStrcpy(buf, bufsize, start) < 0) { + buf[bufsize - 1] = '\0'; + return 0; + } + buf[bufsize - 1] = '\0'; + } + *tok = end; + return buf; +} + +/******************************************************************************/ +/* + * Format a number as a string. + */ + +char *mprItoa(char *buf, int size, int value) +{ + char numBuf[16]; + char *cp, *dp, *endp; + int negative; + + cp = &numBuf[sizeof(numBuf)]; + *--cp = '\0'; + + if (value < 0) { + negative = 1; + value = -value; + size--; + } else { + negative = 0; + } + + do { + *--cp = '0' + (value % 10); + value /= 10; + } while (value > 0); + + if (negative) { + *--cp = '-'; + } + + dp = buf; + endp = &buf[size]; + while (dp < endp && *cp) { + *dp++ = *cp++; + } + *dp++ = '\0'; + return buf; +} + +/******************************************************************************/ +/* + * Parse an ascii number. Supports radix 10 or 16. + */ + +int mprAtoi(const char *str, int radix) +{ + int c, val, negative; + + mprAssert(radix == 10 || radix == 16); + + if (str == 0) { + return 0; + } + + val = 0; + if (radix == 10 && *str == '-') { + negative = 1; + str++; + } else { + negative = 0; + } + + if (radix == 10) { + while (*str && isdigit(*str)) { + val = (val * radix) + *str - '0'; + str++; + } + } else if (radix == 16) { + if (*str == '0' && tolower(str[1]) == 'x') { + str += 2; + } + while (*str) { + c = tolower(*str); + if (isdigit(c)) { + val = (val * radix) + c - '0'; + } else if (c >= 'a' && c <= 'f') { + val = (val * radix) + c - 'a' + 10; + } else { + break; + } + str++; + } + } + + return (negative) ? -val: val; +} + +/******************************************************************************/ +/* + * Make an argv array. Caller must free by calling mprFree(argv) to free + * everything. + */ + +int mprMakeArgv(MprCtx ctx, const char *program, const char *cmd, + char ***argvp, int *argcp) +{ + char *cp, **argv, *buf, *args; + int size, argc; + + /* + * Allocate one buffer for argv and the actual args themselves + */ + size = strlen(cmd) + 1; + + buf = (char*) mprAlloc(ctx, (MPR_MAX_ARGC * sizeof(char*)) + size); + if (buf == 0) { + return MPR_ERR_MEMORY; + } + + args = &buf[MPR_MAX_ARGC * sizeof(char*)]; + strcpy(args, cmd); + argv = (char**) buf; + + argc = 0; + if (program) { + argv[argc++] = (char*) mprStrdup(ctx, program); + } + + for (cp = args; cp && *cp != '\0'; argc++) { + if (argc >= MPR_MAX_ARGC) { + mprAssert(argc < MPR_MAX_ARGC); + mprFree(buf); + *argvp = 0; + if (argcp) { + *argcp = 0; + } + return MPR_ERR_TOO_MANY; + } + while (isspace(*cp)) { + cp++; + } + if (*cp == '\0') { + break; + } + if (*cp == '"') { + cp++; + argv[argc] = cp; + while ((*cp != '\0') && (*cp != '"')) { + cp++; + } + } else { + argv[argc] = cp; + while (*cp != '\0' && !isspace(*cp)) { + cp++; + } + } + if (*cp != '\0') { + *cp++ = '\0'; + } + } + argv[argc] = 0; + + if (argcp) { + *argcp = argc; + } + *argvp = argv; + + return argc; +} + +/******************************************************************************/ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim:tw=78 + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |