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