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