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