/* $NetBSD: strutil.c,v 1.1.1.3 2015/01/17 16:34:18 christos Exp $ */
/*
* Copyright (c) 1997-2014 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry at Imperial College, London.
*
* 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. 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.
*
*
* File: am-utils/libamu/strutil.c
*
*/
/*
* String Utilities.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <am_defs.h>
#include <amu.h>
char *
strnsave(const char *str, int len)
{
char *sp = (char *) xmalloc(len + 1);
memmove(sp, str, len);
sp[len] = '\0';
return sp;
}
/*
* Concatenate three strings and store the result in the buffer pointed to
* by p, making p large enough to hold the strings
*/
char *
str3cat(char *p, char *s1, char *s2, char *s3)
{
int l1 = strlen(s1);
int l2 = strlen(s2);
int l3 = strlen(s3);
p = (char *) xrealloc(p, l1 + l2 + l3 + 1);
memmove(p, s1, l1);
memmove(p + l1, s2, l2);
memmove(p + l1 + l2, s3, l3 + 1);
return p;
}
/*
* Split s using ch as delimiter and qc as quote character
*/
char **
strsplit(char *s, int ch, int qc)
{
char **ivec;
int ic = 0;
int done = 0;
ivec = (char **) xmalloc((ic + 1) * sizeof(char *));
while (!done) {
char *v;
/*
* skip to split char
*/
while (*s && (ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch))
*s++ = '\0';
/*
* End of string?
*/
if (!*s)
break;
/*
* remember start of string
*/
v = s;
/*
* skip to split char
*/
while (*s && !(ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) {
if (*s++ == qc) {
/*
* Skip past string.
*/
s++;
while (*s && *s != qc)
s++;
if (*s == qc)
s++;
}
}
if (!*s)
done = 1;
*s++ = '\0';
/*
* save string in new ivec slot
*/
ivec[ic++] = v;
ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *));
if (amuDebug(D_STR))
plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
}
if (amuDebug(D_STR))
plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
ivec[ic] = NULL;
return ivec;
}
/*
* Use generic strlcpy to copy a string more carefully, null-terminating it
* as needed. However, if the copied string was truncated due to lack of
* space, then warn us.
*
* For now, xstrlcpy returns VOID because it doesn't look like anywhere in
* the Amd code do we actually use the return value of strncpy/strlcpy.
*/
void
#ifdef DEBUG
_xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len)
#else /* not DEBUG */
xstrlcpy(char *dst, const char *src, size_t len)
#endif /* not DEBUG */
{
if (len == 0)
return;
if (strlcpy(dst, src, len) >= len)
#ifdef DEBUG
plog(XLOG_ERROR, "xstrlcpy(%s:%d): string \"%s\" truncated to \"%s\"",
filename, lineno, src, dst);
#else /* not DEBUG */
plog(XLOG_ERROR, "xstrlcpy: string \"%s\" truncated to \"%s\"", src, dst);
#endif /* not DEBUG */
}
/*
* Use generic strlcat to concatenate a string more carefully,
* null-terminating it as needed. However, if the copied string was
* truncated due to lack of space, then warn us.
*
* For now, xstrlcat returns VOID because it doesn't look like anywhere in
* the Amd code do we actually use the return value of strncat/strlcat.
*/
void
#ifdef DEBUG
_xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len)
#else /* not DEBUG */
xstrlcat(char *dst, const char *src, size_t len)
#endif /* not DEBUG */
{
if (len == 0)
return;
if (strlcat(dst, src, len) >= len) {
/* strlcat does not null terminate if the size of src is equal to len. */
dst[strlen(dst) - 1] = '\0';
#ifdef DEBUG
plog(XLOG_ERROR, "xstrlcat(%s:%d): string \"%s\" truncated to \"%s\"",
filename, lineno, src, dst);
#else /* not DEBUG */
plog(XLOG_ERROR, "xstrlcat: string \"%s\" truncated to \"%s\"", src, dst);
#endif /* not DEBUG */
}
}
/* our version of snprintf */
int
#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
_xsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, ...)
#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
xsnprintf(char *str, size_t size, const char *format, ...)
#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
{
va_list ap;
int ret = 0;
va_start(ap, format);
#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
ret = _xvsnprintf(filename, lineno, str, size, format, ap);
#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
ret = xvsnprintf(str, size, format, ap);
#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
va_end(ap);
return ret;
}
/* our version of vsnprintf */
int
#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
_xvsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, va_list ap)
#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
{
int ret = 0;
#ifdef HAVE_VSNPRINTF
ret = vsnprintf(str, size, format, ap);
#else /* not HAVE_VSNPRINTF */
ret = vsprintf(str, format, ap); /* less secure version */
#endif /* not HAVE_VSNPRINTF */
/*
* If error or truncation, plog error.
*
* WARNING: we use the static 'maxtrunc' variable below to break out any
* possible infinite recursion between plog() and xvsnprintf(). If it
* ever happens, it'd indicate a bug in Amd.
*/
if (ret < 0 || (size_t) ret >= size) { /* error or truncation occured */
static int maxtrunc; /* hack to avoid inifinite loop */
if (++maxtrunc > 10)
#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS))
plog(XLOG_ERROR, "xvsnprintf(%s:%d): string %p truncated (ret=%d, format=\"%s\")",
filename, lineno, str, ret, format);
#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
plog(XLOG_ERROR, "xvsnprintf: string %p truncated (ret=%d, format=\"%s\")",
str, ret, format);
#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */
}
return ret;
}
static size_t
vstrlen(const char *src, va_list ap)
{
size_t len = strlen(src);
while ((src = va_arg(ap, const char *)) != NULL)
len += strlen(src);
return len;
}
static void
vstrcpy(char *dst, const char *src, va_list ap)
{
strcpy(dst, src);
while ((src = va_arg(ap, const char *)) != NULL)
strcat(dst, src);
}
char *
strvcat(const char *src, ...)
{
size_t len;
char *dst;
va_list ap;
va_start(ap, src);
len = vstrlen(src, ap);
va_end(ap);
dst = xmalloc(len + 1);
va_start(ap, src);
vstrcpy(dst, src, ap);
va_end(ap);
return dst;
}