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