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