1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-16 00:23:52 +03:00
Files
samba-mirror/source/lib/appweb/ejs-2.0/mpr/mprString.c
Andrew Bartlett 72ca8e3b2a r23961: Allow SWAT to operate on x86_64 machines.
On machines with a 4 byte int, and a 8 byte pointer, the ESP could would fail.

The problem is that 0 != NULL.  0 is an int (4 bytes) and NULL is a
pointer (8), and this matters critically to varargs functions.

If a 0 was passed as the 'terminating' argument, then only 4 bytes
would be written to the stack, but va_arg(ap, char *) would try and
pull 8, reading uninitalised memory.

Andrew Bartlett
2007-10-10 15:01:11 -05:00

734 lines
14 KiB
C

/**
* @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
*/