strutil.c revision 1.1.1.1
1/* $NetBSD: strutil.c,v 1.1.1.1 2008/09/19 20:07:22 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997-2007 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgment: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * 42 * File: am-utils/libamu/strutil.c 43 * 44 */ 45 46/* 47 * String Utilities. 48 */ 49 50#ifdef HAVE_CONFIG_H 51# include <config.h> 52#endif /* HAVE_CONFIG_H */ 53#include <am_defs.h> 54#include <amu.h> 55 56 57char * 58strnsave(const char *str, int len) 59{ 60 char *sp = (char *) xmalloc(len + 1); 61 memmove(sp, str, len); 62 sp[len] = '\0'; 63 64 return sp; 65} 66 67 68/* 69 * Concatenate three strings and store the result in the buffer pointed to 70 * by p, making p large enough to hold the strings 71 */ 72char * 73str3cat(char *p, char *s1, char *s2, char *s3) 74{ 75 int l1 = strlen(s1); 76 int l2 = strlen(s2); 77 int l3 = strlen(s3); 78 79 p = (char *) xrealloc(p, l1 + l2 + l3 + 1); 80 memmove(p, s1, l1); 81 memmove(p + l1, s2, l2); 82 memmove(p + l1 + l2, s3, l3 + 1); 83 return p; 84} 85 86 87/* 88 * Split s using ch as delimiter and qc as quote character 89 */ 90char ** 91strsplit(char *s, int ch, int qc) 92{ 93 char **ivec; 94 int ic = 0; 95 int done = 0; 96 97 ivec = (char **) xmalloc((ic + 1) * sizeof(char *)); 98 99 while (!done) { 100 char *v; 101 102 /* 103 * skip to split char 104 */ 105 while (*s && (ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) 106 *s++ = '\0'; 107 108 /* 109 * End of string? 110 */ 111 if (!*s) 112 break; 113 114 /* 115 * remember start of string 116 */ 117 v = s; 118 119 /* 120 * skip to split char 121 */ 122 while (*s && !(ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) { 123 if (*s++ == qc) { 124 /* 125 * Skip past string. 126 */ 127 s++; 128 while (*s && *s != qc) 129 s++; 130 if (*s == qc) 131 s++; 132 } 133 } 134 135 if (!*s) 136 done = 1; 137 *s++ = '\0'; 138 139 /* 140 * save string in new ivec slot 141 */ 142 ivec[ic++] = v; 143 ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *)); 144 if (amuDebug(D_STR)) 145 plog(XLOG_DEBUG, "strsplit saved \"%s\"", v); 146 } 147 148 if (amuDebug(D_STR)) 149 plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic); 150 151 ivec[ic] = NULL; 152 153 return ivec; 154} 155 156 157/* 158 * Use generic strlcpy to copy a string more carefully, null-terminating it 159 * as needed. However, if the copied string was truncated due to lack of 160 * space, then warn us. 161 * 162 * For now, xstrlcpy returns VOID because it doesn't look like anywhere in 163 * the Amd code do we actually use the return value of strncpy/strlcpy. 164 */ 165void 166#ifdef DEBUG 167_xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len) 168#else /* not DEBUG */ 169xstrlcpy(char *dst, const char *src, size_t len) 170#endif /* not DEBUG */ 171{ 172 if (len == 0) 173 return; 174 if (strlcpy(dst, src, len) >= len) 175#ifdef DEBUG 176 plog(XLOG_ERROR, "xstrlcpy(%s:%d): string \"%s\" truncated to \"%s\"", 177 filename, lineno, src, dst); 178#else /* not DEBUG */ 179 plog(XLOG_ERROR, "xstrlcpy: string \"%s\" truncated to \"%s\"", src, dst); 180#endif /* not DEBUG */ 181} 182 183 184/* 185 * Use generic strlcat to concatenate a string more carefully, 186 * null-terminating it as needed. However, if the copied string was 187 * truncated due to lack of space, then warn us. 188 * 189 * For now, xstrlcat returns VOID because it doesn't look like anywhere in 190 * the Amd code do we actually use the return value of strncat/strlcat. 191 */ 192void 193#ifdef DEBUG 194_xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len) 195#else /* not DEBUG */ 196xstrlcat(char *dst, const char *src, size_t len) 197#endif /* not DEBUG */ 198{ 199 if (len == 0) 200 return; 201 if (strlcat(dst, src, len) >= len) { 202 /* strlcat does not null terminate if the size of src is equal to len. */ 203 dst[strlen(dst) - 1] = '\0'; 204#ifdef DEBUG 205 plog(XLOG_ERROR, "xstrlcat(%s:%d): string \"%s\" truncated to \"%s\"", 206 filename, lineno, src, dst); 207#else /* not DEBUG */ 208 plog(XLOG_ERROR, "xstrlcat: string \"%s\" truncated to \"%s\"", src, dst); 209#endif /* not DEBUG */ 210 } 211} 212 213 214/* our version of snprintf */ 215int 216#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 217_xsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, ...) 218#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 219xsnprintf(char *str, size_t size, const char *format, ...) 220#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 221{ 222 va_list ap; 223 int ret = 0; 224 225 va_start(ap, format); 226#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 227 ret = _xvsnprintf(filename, lineno, str, size, format, ap); 228#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 229 ret = xvsnprintf(str, size, format, ap); 230#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 231 va_end(ap); 232 233 return ret; 234} 235 236 237/* our version of vsnprintf */ 238int 239#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 240_xvsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, va_list ap) 241#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 242xvsnprintf(char *str, size_t size, const char *format, va_list ap) 243#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 244{ 245 int ret = 0; 246 247#ifdef HAVE_VSNPRINTF 248 ret = vsnprintf(str, size, format, ap); 249#else /* not HAVE_VSNPRINTF */ 250 ret = vsprintf(str, format, ap); /* less secure version */ 251#endif /* not HAVE_VSNPRINTF */ 252 /* 253 * If error or truncation, plog error. 254 * 255 * WARNING: we use the static 'maxtrunc' variable below to break out any 256 * possible infinite recursion between plog() and xvsnprintf(). If it 257 * ever happens, it'd indicate a bug in Amd. 258 */ 259 if (ret < 0 || (size_t) ret >= size) { /* error or truncation occured */ 260 static int maxtrunc; /* hack to avoid inifinite loop */ 261 if (++maxtrunc > 10) 262#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 263 plog(XLOG_ERROR, "xvsnprintf(%s:%d): string %p truncated (ret=%d, format=\"%s\")", 264 filename, lineno, str, ret, format); 265#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 266 plog(XLOG_ERROR, "xvsnprintf: string %p truncated (ret=%d, format=\"%s\")", 267 str, ret, format); 268#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 269 } 270 271 return ret; 272} 273