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