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