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