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 51 char * 52 strnsave(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 */ 66 char * 67 str3cat(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 */ 84 char ** 85 strsplit(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 */ 159 void 160 #ifdef DEBUG 161 _xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len) 162 #else /* not DEBUG */ 163 xstrlcpy(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 */ 186 void 187 #ifdef DEBUG 188 _xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len) 189 #else /* not DEBUG */ 190 xstrlcat(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 */ 209 int 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 */ 213 xsnprintf(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 */ 232 int 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 */ 236 xvsnprintf(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 268 static size_t 269 vstrlen(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 277 static void 278 vstrcpy(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 285 char * 286 strvcat(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