xref: /netbsd-src/external/bsd/am-utils/dist/libamu/strutil.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: strutil.c,v 1.1.1.2 2009/03/20 20:26:56 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2009 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 
57 char *
58 strnsave(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  */
72 char *
73 str3cat(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  */
90 char **
91 strsplit(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  */
165 void
166 #ifdef DEBUG
167 _xstrlcpy(const char *filename, int lineno, char *dst, const char *src, size_t len)
168 #else /* not DEBUG */
169 xstrlcpy(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  */
192 void
193 #ifdef DEBUG
194 _xstrlcat(const char *filename, int lineno, char *dst, const char *src, size_t len)
195 #else /* not DEBUG */
196 xstrlcat(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 */
215 int
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 */
219 xsnprintf(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 */
238 int
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 */
242 xvsnprintf(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