1174294Sobrien/* 2310490Scy * Copyright (c) 1997-2014 Erez Zadok 3174294Sobrien * Copyright (c) 1990 Jan-Simon Pendry 4174294Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5174294Sobrien * Copyright (c) 1990 The Regents of the University of California. 6174294Sobrien * All rights reserved. 7174294Sobrien * 8174294Sobrien * This code is derived from software contributed to Berkeley by 9174294Sobrien * Jan-Simon Pendry at Imperial College, London. 10174294Sobrien * 11174294Sobrien * Redistribution and use in source and binary forms, with or without 12174294Sobrien * modification, are permitted provided that the following conditions 13174294Sobrien * are met: 14174294Sobrien * 1. Redistributions of source code must retain the above copyright 15174294Sobrien * notice, this list of conditions and the following disclaimer. 16174294Sobrien * 2. Redistributions in binary form must reproduce the above copyright 17174294Sobrien * notice, this list of conditions and the following disclaimer in the 18174294Sobrien * documentation and/or other materials provided with the distribution. 19310490Scy * 3. Neither the name of the University nor the names of its contributors 20174294Sobrien * may be used to endorse or promote products derived from this software 21174294Sobrien * without specific prior written permission. 22174294Sobrien * 23174294Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24174294Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25174294Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26174294Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27174294Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28174294Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29174294Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30174294Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31174294Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32174294Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33174294Sobrien * SUCH DAMAGE. 34174294Sobrien * 35174294Sobrien * 36174294Sobrien * File: am-utils/libamu/strutil.c 37174294Sobrien * 38174294Sobrien */ 39174294Sobrien 40174294Sobrien/* 41174294Sobrien * String Utilities. 42174294Sobrien */ 43174294Sobrien 44174294Sobrien#ifdef HAVE_CONFIG_H 45174294Sobrien# include <config.h> 46174294Sobrien#endif /* HAVE_CONFIG_H */ 47174294Sobrien#include <am_defs.h> 48174294Sobrien#include <amu.h> 49174294Sobrien 50174294Sobrien 51174294Sobrienchar * 52174294Sobrienstrnsave(const char *str, int len) 53174294Sobrien{ 54174294Sobrien char *sp = (char *) xmalloc(len + 1); 55174294Sobrien memmove(sp, str, len); 56174294Sobrien sp[len] = '\0'; 57174294Sobrien 58174294Sobrien return sp; 59174294Sobrien} 60174294Sobrien 61174294Sobrien 62174294Sobrien/* 63174294Sobrien * Concatenate three strings and store the result in the buffer pointed to 64174294Sobrien * by p, making p large enough to hold the strings 65174294Sobrien */ 66174294Sobrienchar * 67174294Sobrienstr3cat(char *p, char *s1, char *s2, char *s3) 68174294Sobrien{ 69174294Sobrien int l1 = strlen(s1); 70174294Sobrien int l2 = strlen(s2); 71174294Sobrien int l3 = strlen(s3); 72174294Sobrien 73174294Sobrien p = (char *) xrealloc(p, l1 + l2 + l3 + 1); 74174294Sobrien memmove(p, s1, l1); 75174294Sobrien memmove(p + l1, s2, l2); 76174294Sobrien memmove(p + l1 + l2, s3, l3 + 1); 77174294Sobrien return p; 78174294Sobrien} 79174294Sobrien 80174294Sobrien 81174294Sobrien/* 82174294Sobrien * Split s using ch as delimiter and qc as quote character 83174294Sobrien */ 84174294Sobrienchar ** 85174294Sobrienstrsplit(char *s, int ch, int qc) 86174294Sobrien{ 87174294Sobrien char **ivec; 88174294Sobrien int ic = 0; 89174294Sobrien int done = 0; 90174294Sobrien 91174294Sobrien ivec = (char **) xmalloc((ic + 1) * sizeof(char *)); 92174294Sobrien 93174294Sobrien while (!done) { 94174294Sobrien char *v; 95174294Sobrien 96174294Sobrien /* 97174294Sobrien * skip to split char 98174294Sobrien */ 99174294Sobrien while (*s && (ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) 100174294Sobrien *s++ = '\0'; 101174294Sobrien 102174294Sobrien /* 103174294Sobrien * End of string? 104174294Sobrien */ 105174294Sobrien if (!*s) 106174294Sobrien break; 107174294Sobrien 108174294Sobrien /* 109174294Sobrien * remember start of string 110174294Sobrien */ 111174294Sobrien v = s; 112174294Sobrien 113174294Sobrien /* 114174294Sobrien * skip to split char 115174294Sobrien */ 116174294Sobrien while (*s && !(ch == ' ' ? (isascii((unsigned char)*s) && isspace((unsigned char)*s)) : *s == ch)) { 117174294Sobrien if (*s++ == qc) { 118174294Sobrien /* 119174294Sobrien * Skip past string. 120174294Sobrien */ 121174294Sobrien s++; 122174294Sobrien while (*s && *s != qc) 123174294Sobrien s++; 124174294Sobrien if (*s == qc) 125174294Sobrien s++; 126174294Sobrien } 127174294Sobrien } 128174294Sobrien 129174294Sobrien if (!*s) 130174294Sobrien done = 1; 131174294Sobrien *s++ = '\0'; 132174294Sobrien 133174294Sobrien /* 134174294Sobrien * save string in new ivec slot 135174294Sobrien */ 136174294Sobrien ivec[ic++] = v; 137174294Sobrien ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *)); 138174294Sobrien if (amuDebug(D_STR)) 139174294Sobrien plog(XLOG_DEBUG, "strsplit saved \"%s\"", v); 140174294Sobrien } 141174294Sobrien 142174294Sobrien if (amuDebug(D_STR)) 143174294Sobrien plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic); 144174294Sobrien 145174294Sobrien ivec[ic] = NULL; 146174294Sobrien 147174294Sobrien return ivec; 148174294Sobrien} 149174294Sobrien 150174294Sobrien 151174294Sobrien/* 152174294Sobrien * Use generic strlcpy to copy a string more carefully, null-terminating it 153174294Sobrien * as needed. However, if the copied string was truncated due to lack of 154174294Sobrien * space, then warn us. 155174294Sobrien * 156174294Sobrien * For now, xstrlcpy returns VOID because it doesn't look like anywhere in 157174294Sobrien * the Amd code do we actually use the return value of strncpy/strlcpy. 158174294Sobrien */ 159174294Sobrienvoid 160174294Sobrien#ifdef DEBUG 161174294Sobrien_xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len) 162174294Sobrien#else /* not DEBUG */ 163174294Sobrienxstrlcpy(char *dst, const char *src, size_t len) 164174294Sobrien#endif /* not DEBUG */ 165174294Sobrien{ 166174294Sobrien if (len == 0) 167174294Sobrien return; 168174294Sobrien if (strlcpy(dst, src, len) >= len) 169174294Sobrien#ifdef DEBUG 170174294Sobrien plog(XLOG_ERROR, "xstrlcpy(%s:%d): string \"%s\" truncated to \"%s\"", 171174294Sobrien filename, lineno, src, dst); 172174294Sobrien#else /* not DEBUG */ 173174294Sobrien plog(XLOG_ERROR, "xstrlcpy: string \"%s\" truncated to \"%s\"", src, dst); 174174294Sobrien#endif /* not DEBUG */ 175174294Sobrien} 176174294Sobrien 177174294Sobrien 178174294Sobrien/* 179174294Sobrien * Use generic strlcat to concatenate a string more carefully, 180174294Sobrien * null-terminating it as needed. However, if the copied string was 181174294Sobrien * truncated due to lack of space, then warn us. 182174294Sobrien * 183174294Sobrien * For now, xstrlcat returns VOID because it doesn't look like anywhere in 184174294Sobrien * the Amd code do we actually use the return value of strncat/strlcat. 185174294Sobrien */ 186174294Sobrienvoid 187174294Sobrien#ifdef DEBUG 188174294Sobrien_xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len) 189174294Sobrien#else /* not DEBUG */ 190174294Sobrienxstrlcat(char *dst, const char *src, size_t len) 191174294Sobrien#endif /* not DEBUG */ 192174294Sobrien{ 193174294Sobrien if (len == 0) 194174294Sobrien return; 195174294Sobrien if (strlcat(dst, src, len) >= len) { 196174294Sobrien /* strlcat does not null terminate if the size of src is equal to len. */ 197174294Sobrien dst[strlen(dst) - 1] = '\0'; 198174294Sobrien#ifdef DEBUG 199174294Sobrien plog(XLOG_ERROR, "xstrlcat(%s:%d): string \"%s\" truncated to \"%s\"", 200174294Sobrien filename, lineno, src, dst); 201174294Sobrien#else /* not DEBUG */ 202174294Sobrien plog(XLOG_ERROR, "xstrlcat: string \"%s\" truncated to \"%s\"", src, dst); 203174294Sobrien#endif /* not DEBUG */ 204174294Sobrien } 205174294Sobrien} 206174294Sobrien 207174294Sobrien 208174294Sobrien/* our version of snprintf */ 209174294Sobrienint 210174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 211174294Sobrien_xsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, ...) 212174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 213174294Sobrienxsnprintf(char *str, size_t size, const char *format, ...) 214174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 215174294Sobrien{ 216174294Sobrien va_list ap; 217174294Sobrien int ret = 0; 218174294Sobrien 219174294Sobrien va_start(ap, format); 220174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 221174294Sobrien ret = _xvsnprintf(filename, lineno, str, size, format, ap); 222174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 223174294Sobrien ret = xvsnprintf(str, size, format, ap); 224174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 225174294Sobrien va_end(ap); 226174294Sobrien 227174294Sobrien return ret; 228174294Sobrien} 229174294Sobrien 230174294Sobrien 231174294Sobrien/* our version of vsnprintf */ 232174294Sobrienint 233174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 234174294Sobrien_xvsnprintf(const char *filename, int lineno, char *str, size_t size, const char *format, va_list ap) 235174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 236174294Sobrienxvsnprintf(char *str, size_t size, const char *format, va_list ap) 237174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 238174294Sobrien{ 239174294Sobrien int ret = 0; 240174294Sobrien 241174294Sobrien#ifdef HAVE_VSNPRINTF 242174294Sobrien ret = vsnprintf(str, size, format, ap); 243174294Sobrien#else /* not HAVE_VSNPRINTF */ 244174294Sobrien ret = vsprintf(str, format, ap); /* less secure version */ 245174294Sobrien#endif /* not HAVE_VSNPRINTF */ 246174294Sobrien /* 247174294Sobrien * If error or truncation, plog error. 248174294Sobrien * 249174294Sobrien * WARNING: we use the static 'maxtrunc' variable below to break out any 250174294Sobrien * possible infinite recursion between plog() and xvsnprintf(). If it 251174294Sobrien * ever happens, it'd indicate a bug in Amd. 252174294Sobrien */ 253174294Sobrien if (ret < 0 || (size_t) ret >= size) { /* error or truncation occured */ 254174294Sobrien static int maxtrunc; /* hack to avoid inifinite loop */ 255174294Sobrien if (++maxtrunc > 10) 256174294Sobrien#if defined(DEBUG) && (defined(HAVE_C99_VARARGS_MACROS) || defined(HAVE_GCC_VARARGS_MACROS)) 257174294Sobrien plog(XLOG_ERROR, "xvsnprintf(%s:%d): string %p truncated (ret=%d, format=\"%s\")", 258174294Sobrien filename, lineno, str, ret, format); 259174294Sobrien#else /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 260174294Sobrien plog(XLOG_ERROR, "xvsnprintf: string %p truncated (ret=%d, format=\"%s\")", 261174294Sobrien str, ret, format); 262174294Sobrien#endif /* not DEBUG or no C99/GCC-style vararg cpp macros supported */ 263174294Sobrien } 264174294Sobrien 265174294Sobrien return ret; 266174294Sobrien} 267310490Scy 268310490Scystatic size_t 269310490Scyvstrlen(const char *src, va_list ap) 270310490Scy{ 271310490Scy size_t len = strlen(src); 272310490Scy while ((src = va_arg(ap, const char *)) != NULL) 273310490Scy len += strlen(src); 274310490Scy return len; 275310490Scy} 276310490Scy 277310490Scystatic void 278310490Scyvstrcpy(char *dst, const char *src, va_list ap) 279310490Scy{ 280310490Scy strcpy(dst, src); 281310490Scy while ((src = va_arg(ap, const char *)) != NULL) 282310490Scy strcat(dst, src); 283310490Scy} 284310490Scy 285310490Scychar * 286310490Scystrvcat(const char *src, ...) 287310490Scy{ 288310490Scy size_t len; 289310490Scy char *dst; 290310490Scy va_list ap; 291310490Scy 292310490Scy va_start(ap, src); 293310490Scy len = vstrlen(src, ap); 294310490Scy va_end(ap); 295310490Scy dst = xmalloc(len + 1); 296310490Scy va_start(ap, src); 297310490Scy vstrcpy(dst, src, ap); 298310490Scy va_end(ap); 299310490Scy return dst; 300310490Scy} 301