0fbead42442ae4697da6b3a71da7da8a96900f06
[wmaker-crm.git] / WINGs / string.c
blob0fbead42442ae4697da6b3a71da7da8a96900f06
1 /*
2 * Until FreeBSD gets their act together;
3 * http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
4 */
5 #if defined( FREEBSD )
6 # undef _XOPEN_SOURCE
7 #endif
9 #include "wconfig.h"
11 #include <string.h>
12 #include <stdlib.h>
13 #include <assert.h>
14 #include <ctype.h>
15 #ifdef HAVE_BSD_STRING_H
16 #include <bsd/string.h>
17 #endif
19 #include "WUtil.h"
21 #define PRC_ALPHA 0
22 #define PRC_BLANK 1
23 #define PRC_ESCAPE 2
24 #define PRC_DQUOTE 3
25 #define PRC_EOS 4
26 #define PRC_SQUOTE 5
28 typedef struct {
29 short nstate;
30 short output;
31 } DFA;
33 static DFA mtable[9][6] = {
34 {{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
35 {{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
36 {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
37 {{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
38 {{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
39 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
40 {{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
41 {{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
42 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
45 char *wtokennext(char *word, char **next)
47 char *ptr;
48 char *ret, *t;
49 int state, ctype;
51 t = ret = wmalloc(strlen(word) + 1);
52 ptr = word;
54 state = 0;
55 while (1) {
56 if (*ptr == 0)
57 ctype = PRC_EOS;
58 else if (*ptr == '\\')
59 ctype = PRC_ESCAPE;
60 else if (*ptr == '"')
61 ctype = PRC_DQUOTE;
62 else if (*ptr == '\'')
63 ctype = PRC_SQUOTE;
64 else if (*ptr == ' ' || *ptr == '\t')
65 ctype = PRC_BLANK;
66 else
67 ctype = PRC_ALPHA;
69 if (mtable[state][ctype].output) {
70 *t = *ptr;
71 t++;
72 *t = 0;
74 state = mtable[state][ctype].nstate;
75 ptr++;
76 if (mtable[state][0].output < 0) {
77 break;
81 if (*ret == 0) {
82 wfree(ret);
83 ret = NULL;
86 if (ctype == PRC_EOS)
87 *next = NULL;
88 else
89 *next = ptr;
91 return ret;
94 /* separate a string in tokens, taking " and ' into account */
95 void wtokensplit(char *command, char ***argv, int *argc)
97 char *token, *line;
98 int count;
100 count = 0;
101 line = command;
102 do {
103 token = wtokennext(line, &line);
104 if (token) {
105 if (count == 0)
106 *argv = wmalloc(sizeof(char **));
107 else
108 *argv = wrealloc(*argv, (count + 1) * sizeof(char **));
109 (*argv)[count++] = token;
111 } while (token != NULL && line != NULL);
113 *argc = count;
116 char *wtokenjoin(char **list, int count)
118 int i, j;
119 char *flat_string, *wspace;
121 j = 0;
122 for (i = 0; i < count; i++) {
123 if (list[i] != NULL && list[i][0] != 0) {
124 j += strlen(list[i]);
125 if (strpbrk(list[i], " \t"))
126 j += 2;
130 flat_string = wmalloc(j + count + 1);
132 for (i = 0; i < count; i++) {
133 if (list[i] != NULL && list[i][0] != 0) {
134 if (i > 0 &&
135 wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
136 goto error;
138 wspace = strpbrk(list[i], " \t");
140 if (wspace &&
141 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
142 goto error;
144 if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
145 goto error;
147 if (wspace &&
148 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
149 goto error;
153 return flat_string;
155 error:
156 wfree(flat_string);
158 return NULL;
161 void wtokenfree(char **tokens, int count)
163 while (count--)
164 wfree(tokens[count]);
165 wfree(tokens);
168 char *wtrimspace(const char *s)
170 const char *t;
172 if (s == NULL)
173 return NULL;
175 while (isspace(*s) && *s)
176 s++;
177 t = s + strlen(s) - 1;
178 while (t > s && isspace(*t))
179 t--;
181 return wstrndup(s, t - s + 1);
184 char *wstrdup(const char *str)
186 assert(str != NULL);
188 return strcpy(wmalloc(strlen(str) + 1), str);
191 char *wstrndup(const char *str, size_t len)
193 char *copy;
195 assert(str != NULL);
197 len = WMIN(len, strlen(str));
198 copy = strncpy(wmalloc(len + 1), str, len);
199 copy[len] = 0;
201 return copy;
204 char *wstrconcat(const char *str1, const char *str2)
206 char *str;
207 size_t slen;
209 if (!str1 && str2)
210 return wstrdup(str2);
211 else if (str1 && !str2)
212 return wstrdup(str1);
213 else if (!str1 && !str2)
214 return NULL;
216 slen = strlen(str1) + strlen(str2) + 1;
217 str = wmalloc(slen);
218 if (wstrlcpy(str, str1, slen) >= slen ||
219 wstrlcat(str, str2, slen) >= slen) {
220 wfree(str);
221 return NULL;
224 return str;
227 char *wstrappend(char *dst, const char *src)
229 size_t slen;
231 if (!src || *src == 0)
232 return dst;
233 else if (!dst)
234 return wstrdup(src);
236 slen = strlen(dst) + strlen(src) + 1;
237 dst = wrealloc(dst, slen);
238 if (wstrlcat(dst, src, slen) >= slen)
239 return NULL;
241 return dst;
245 #if HAVE_STRLCAT
246 size_t
247 wstrlcat(char *dst, const char *src, size_t siz)
249 return strlcat(dst, src, siz);
251 #else
252 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
255 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
257 * Permission to use, copy, modify, and distribute this software for any
258 * purpose with or without fee is hereby granted, provided that the above
259 * copyright notice and this permission notice appear in all copies.
261 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
262 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
263 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
264 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
265 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
266 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
267 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
271 * Appends src to string dst of size siz (unlike strncat, siz is the
272 * full size of dst, not space left). At most siz-1 characters
273 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
274 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
275 * If retval >= siz, truncation occurred.
277 size_t
278 wstrlcat(char *dst, const char *src, size_t siz)
280 char *d = dst;
281 const char *s = src;
282 size_t n = siz;
283 size_t dlen;
285 /* Find the end of dst and adjust bytes left but don't go past end */
286 while (n-- != 0 && *d != '\0')
287 d++;
288 dlen = d - dst;
289 n = siz - dlen;
291 if (n == 0)
292 return(dlen + strlen(s));
293 while (*s != '\0') {
294 if (n != 1) {
295 *d++ = *s;
296 n--;
298 s++;
300 *d = '\0';
302 return(dlen + (s - src)); /* count does not include NUL */
304 #endif /* HAVE_STRLCAT */
306 #if HAVE_STRLCPY
307 size_t
308 wstrlcpy(char *dst, const char *src, size_t siz)
310 return strlcpy(dst, src, siz);
312 #else
314 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
317 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
319 * Permission to use, copy, modify, and distribute this software for any
320 * purpose with or without fee is hereby granted, provided that the above
321 * copyright notice and this permission notice appear in all copies.
323 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
324 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
325 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
326 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
327 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
328 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
329 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
333 * Copy src to string dst of size siz. At most siz-1 characters
334 * will be copied. Always NUL terminates (unless siz == 0).
335 * Returns strlen(src); if retval >= siz, truncation occurred.
337 size_t
338 wstrlcpy(char *dst, const char *src, size_t siz)
340 char *d = dst;
341 const char *s = src;
342 size_t n = siz;
344 /* Copy as many bytes as will fit */
345 if (n != 0) {
346 while (--n != 0) {
347 if ((*d++ = *s++) == '\0')
348 break;
352 /* Not enough room in dst, add NUL and traverse rest of src */
353 if (n == 0) {
354 if (siz != 0)
355 *d = '\0'; /* NUL-terminate dst */
356 while (*s++)
360 return(s - src - 1); /* count does not include NUL */
362 #endif /* HAVE_STRLCPY */
364 /* transform `s' so that the result is safe to pass to the shell as an argument.
365 * returns a newly allocated string.
366 * with very heavy inspirations from NetBSD's shquote(3).
368 char *wshellquote(const char *s)
370 char *p, *r, *last, *ret;
371 size_t slen;
372 int needs_quoting;
374 if (!s)
375 return NULL;
377 needs_quoting = !*s; /* the empty string does need quoting */
379 /* do not quote if consists only of the following characters */
380 for (p = (char *)s; *p && !needs_quoting; p++) {
381 needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
382 (*p == '.') || (*p == ',') || (*p == '-'));
385 if (!needs_quoting)
386 return wstrdup(s);
388 for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
389 slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
391 slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
393 ret = r = wmalloc(slen);
394 p = (char *)s;
395 last = p;
397 if (*p != '\'') /* if string doesn't already begin with "'" */
398 *r++ ='\''; /* start putting it in quotes */
400 while (*p) {
401 last = p;
402 if (*p == '\'') { /* turn each ' into ''\' */
403 if (p != s) /* except if it's the first ', in which case */
404 *r++ = '\''; /* only escape it */
405 *r++ = '\\';
406 *r++ = '\'';
407 while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
408 *r++ = '\\';
409 *r++ = '\'';
411 if (*p) /* if more input follows, terminate */
412 *r++ = '\''; /* what we have so far */
413 } else {
414 *r++ = *p++;
418 if (*last != '\'') /* if the last one isn't already a ' */
419 *r++ = '\''; /* terminate the whole shebang */
421 *r = '\0';
423 return ret; /* technically, we lose (but not leak) a couple of */
424 /* bytes (twice the number of consecutive 's in the */
425 /* input or so), but since these are relatively rare */
426 /* and short-lived strings, not sure if a trip to */
427 /* wstrdup+wfree worths the gain. */