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