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