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