ossp-pkg/str/str_basic.c
/*
** OSSP str - String Handling
** Copyright (c) 1999-2005 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 1999-2005 The OSSP Project <http://www.ossp.org/>
**
** This file is part of OSSP str, a string handling and manipulation
** library which can be found at http://www.ossp.org/pkg/lib/str/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** 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.
**
** str_handle.c: handling and manipulation functions
*/
#include "str_p.h"
/*
* str_len -- determine length of string.
* This is exactly equal to POSIX strlen(3).
*/
str_size_t str_len(const char *s)
{
register const char *t;
if (s == NULL)
return 0;
t = s;
while (*t++ != NUL)
/*nop*/;
return (t-s-1);
}
/*
* str_copy -- copy a string.
* This is inspired by POSIX strncpy(3), but the source and target
* and overlap and the the target is always NUL-terminated.
*/
char *str_copy(char *as, const char *at, str_size_t n)
{
register char *s;
register const char *t;
char *rv;
if (as == NULL || at == NULL)
return NULL;
if (n == 0)
n = str_len(at);
t = at;
s = as;
rv = as;
if (s > t) {
/* must go high to low */
t += n - 1;
s += n;
rv = s;
*s-- = NUL;
while (n-- > 0)
*s-- = *t--;
}
else if (s < t) {
/* must go low to high */
while (n-- > 0)
*s++ = *t++;
*s = NUL;
rv = s;
}
return rv;
}
/*
* str_dup -- duplicate a string.
* This is inspired by POSIX strdup(3), but provides
* the ability to specify a maximum length.
*/
char *str_dup(const char *s, str_size_t n)
{
char *t;
char *rv;
if (s == NULL)
return NULL;
if (n == 0)
n = str_len(s);
if ((rv = str_mem_alloc(n+1)) == NULL)
return NULL;
t = rv;
while (n-- > 0)
*t++ = *s++;
*t = NUL;
return rv;
}
/*
* str_concat -- concatenate one or more strings.
* This function allows one to concatenate an arbitrary number of
* strings and is inspired by Apache's ap_pstrcat() function.
*/
char *str_concat(char *s, ...)
{
va_list ap;
char *rv;
va_start(ap, s);
rv = str_concat_va(s, ap);
va_end(ap);
return rv;
}
char *str_concat_va(char *s, va_list ap)
{
va_list ap_safe;
int n;
char *rv;
char *cp;
char *ds;
if (s == NULL)
return NULL;
/* determine required target string length */
va_copy(ap_safe, ap);
n = str_len(s);
while ((cp = va_arg(ap, char *)) != NULL)
n += str_len(cp);
va_copy(ap, ap_safe);
/* allocate target string */
if ((rv = str_mem_alloc(n+1)) == NULL)
return NULL;
/* concatenate the strings */
ds = rv;
while ((*ds = *s++) != NUL)
ds++;
while ((cp = va_arg(ap, char *)) != NULL) {
while ((*ds = *cp++) != NUL)
ds++;
}
/* return target string */
return rv;
}
/*
* str_splice -- splice one string into another.
* This is inspired by Perl's splice() function and can be used
* both for inplace movements, insert and cut-out operations.
*/
char *str_splice(char *s, str_size_t off, str_size_t n, char *t, str_size_t m)
{
int sl;
/* check for invalid arguments */
if (s == NULL || t == NULL)
return NULL;
/* check for overlapping areas */
if (!((t+m) <= s || (s+off+n) <= t))
return NULL;
sl = str_len(s);
if ((t+m) < s || (s+sl) < t) {
/* splice _external_ area into internal area */
if (m != n)
str_mem_move(s+off+m, s+off+n, sl-off-n+1);
str_mem_move(s+off, t, m);
}
else {
/* splice _internal_ area into internal area */
if (t > s) {
/* move t from larger to lower address of s */
str_mem_rev(s+off, (t+m)-(s+off));
str_mem_rev(s+off, m);
str_mem_rev(s+off+m, t-(s+n));
str_mem_move(t+m-n, t+m, (s+sl)-(t+m)+1);
}
else {
/* move t from lower to higher address of s */
str_mem_rev(t, (s+off)-t);
str_mem_rev(t, (s+off)-t-m);
str_mem_rev(s+off-m, m);
str_mem_move(s+off, s+off+n, sl-off-n+1);
}
}
return s;
}
/*
* str_compare -- compare a two strings.
* This is inspired by POSIX str[n][case]cmp(3), but
* merges all functionality in a single function.
*/
int str_compare(const char *s1, const char *s2, str_size_t n, int mode)
{
int rv;
int bWithLen;
rv = 0;
if (n == 0)
bWithLen = FALSE;
else
bWithLen = TRUE;
if (mode & STR_NOCASE) {
/* compare case insensitive */
do {
if (str_tolower(*s1) != str_tolower(*s2++)) {
rv = ((str_tolower(*s1) -
str_tolower(*(s2 - 1))) < 0 ? -1 : +1);
break;
}
if (bWithLen)
if (--n <= 0)
break;
} while (*s1++ != NUL);
}
else {
/* compare case sensitive */
do {
if (*s1 != *s2++) {
rv = (((int)(*(const unsigned char *)s1) -
(int)(*(const unsigned char *)(s2 - 1))) < 0 ? -1 : +1);
break;
}
if (bWithLen)
if (--n <= 0)
break;
} while (*s1++ != NUL);
}
return rv;
}