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