xref: /netbsd-src/external/bsd/am-utils/dist/libamu/strutil.c (revision 8bae5d409deb915cf7c8f0539fae22ff2cb8a313)
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