Small update on wmgenmenu list of apps
[wmaker-crm.git] / WINGs / string.c
blobaabad313f46f356a80ce90319be84819dc38e593
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 <ctype.h>
14 #ifdef HAVE_BSD_STRING_H
15 #include <bsd/string.h>
16 #endif
18 #include "WUtil.h"
20 #define PRC_ALPHA 0
21 #define PRC_BLANK 1
22 #define PRC_ESCAPE 2
23 #define PRC_DQUOTE 3
24 #define PRC_EOS 4
25 #define PRC_SQUOTE 5
27 typedef struct {
28 short nstate;
29 short output;
30 } DFA;
32 static DFA mtable[9][6] = {
33 {{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
34 {{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
35 {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
36 {{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
37 {{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
38 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
39 {{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
40 {{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
41 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
44 char *wtokennext(char *word, char **next)
46 char *ptr;
47 char *ret, *t;
48 int state, ctype;
50 t = ret = wmalloc(strlen(word) + 1);
51 ptr = word;
53 state = 0;
54 while (1) {
55 if (*ptr == 0)
56 ctype = PRC_EOS;
57 else if (*ptr == '\\')
58 ctype = PRC_ESCAPE;
59 else if (*ptr == '"')
60 ctype = PRC_DQUOTE;
61 else if (*ptr == '\'')
62 ctype = PRC_SQUOTE;
63 else if (*ptr == ' ' || *ptr == '\t')
64 ctype = PRC_BLANK;
65 else
66 ctype = PRC_ALPHA;
68 if (mtable[state][ctype].output) {
69 *t = *ptr;
70 t++;
71 *t = 0;
73 state = mtable[state][ctype].nstate;
74 ptr++;
75 if (mtable[state][0].output < 0) {
76 break;
80 if (*ret == 0)
81 t = NULL;
82 else
83 t = wstrdup(ret);
85 wfree(ret);
87 if (ctype == PRC_EOS)
88 *next = NULL;
89 else
90 *next = ptr;
92 return t;
95 /* separate a string in tokens, taking " and ' into account */
96 void wtokensplit(char *command, char ***argv, int *argc)
98 char *token, *line;
99 int count;
101 count = 0;
102 line = command;
103 do {
104 token = wtokennext(line, &line);
105 if (token) {
106 if (count == 0)
107 *argv = wmalloc(sizeof(char **));
108 else
109 *argv = wrealloc(*argv, (count + 1) * sizeof(char **));
110 (*argv)[count++] = token;
112 } while (token != NULL && line != NULL);
114 *argc = count;
117 char *wtokenjoin(char **list, int count)
119 int i, j;
120 char *flat_string, *wspace;
122 j = 0;
123 for (i = 0; i < count; i++) {
124 if (list[i] != NULL && list[i][0] != 0) {
125 j += strlen(list[i]);
126 if (strpbrk(list[i], " \t"))
127 j += 2;
131 flat_string = wmalloc(j + count + 1);
133 for (i = 0; i < count; i++) {
134 if (list[i] != NULL && list[i][0] != 0) {
135 if (i > 0 &&
136 wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
137 goto error;
139 wspace = strpbrk(list[i], " \t");
141 if (wspace &&
142 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
143 goto error;
145 if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
146 goto error;
148 if (wspace &&
149 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
150 goto error;
154 return flat_string;
156 error:
157 wfree(flat_string);
159 return NULL;
162 void wtokenfree(char **tokens, int count)
164 while (count--)
165 wfree(tokens[count]);
166 wfree(tokens);
169 char *wtrimspace(const char *s)
171 char *t;
173 if (s == NULL)
174 return NULL;
176 while (isspace(*s) && *s)
177 s++;
178 t = (char *)s + strlen(s) - 1;
179 while (t > s && isspace(*t))
180 t--;
182 return wstrndup(s, t - s + 1);
185 char *wstrdup(const char *str)
187 assert(str != NULL);
189 return strcpy(wmalloc(strlen(str) + 1), str);
192 char *wstrndup(const char *str, size_t len)
194 char *copy;
196 assert(str != NULL);
198 len = WMIN(len, strlen(str));
199 copy = strncpy(wmalloc(len + 1), str, len);
200 copy[len] = 0;
202 return copy;
205 char *wstrconcat(char *str1, char *str2)
207 char *str;
208 size_t slen;
210 if (!str1)
211 return wstrdup(str2);
212 else if (!str2)
213 return wstrdup(str1);
215 slen = strlen(str1) + strlen(str2) + 1;
216 str = wmalloc(slen);
217 if (wstrlcpy(str, str1, slen) >= slen ||
218 wstrlcat(str, str2, slen) >= slen) {
219 wfree(str);
220 return NULL;
223 return str;
226 char *wstrappend(char *dst, char *src)
228 size_t slen;
230 if (!dst)
231 return wstrdup(src);
232 else if (!src || *src == 0)
233 return dst;
235 slen = strlen(dst) + strlen(src) + 1;
236 dst = wrealloc(dst, slen);
237 if (wstrlcat(dst, src, slen) >= slen)
238 return NULL;
240 return dst;
244 #if HAVE_STRLCAT
245 size_t
246 wstrlcat(char *dst, const char *src, size_t siz)
248 return strlcat(dst, src, siz);
250 #else
251 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
254 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
256 * Permission to use, copy, modify, and distribute this software for any
257 * purpose with or without fee is hereby granted, provided that the above
258 * copyright notice and this permission notice appear in all copies.
260 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
261 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
262 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
263 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
264 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
265 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
266 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
270 * Appends src to string dst of size siz (unlike strncat, siz is the
271 * full size of dst, not space left). At most siz-1 characters
272 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
273 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
274 * If retval >= siz, truncation occurred.
276 size_t
277 wstrlcat(char *dst, const char *src, size_t siz)
279 char *d = dst;
280 const char *s = src;
281 size_t n = siz;
282 size_t dlen;
284 /* Find the end of dst and adjust bytes left but don't go past end */
285 while (n-- != 0 && *d != '\0')
286 d++;
287 dlen = d - dst;
288 n = siz - dlen;
290 if (n == 0)
291 return(dlen + strlen(s));
292 while (*s != '\0') {
293 if (n != 1) {
294 *d++ = *s;
295 n--;
297 s++;
299 *d = '\0';
301 return(dlen + (s - src)); /* count does not include NUL */
303 #endif /* HAVE_STRLCAT */
305 #if HAVE_STRLCPY
306 size_t
307 wstrlcpy(char *dst, const char *src, size_t siz)
309 return strlcpy(dst, src, siz);
311 #else
313 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
316 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
318 * Permission to use, copy, modify, and distribute this software for any
319 * purpose with or without fee is hereby granted, provided that the above
320 * copyright notice and this permission notice appear in all copies.
322 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
323 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
324 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
325 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
326 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
327 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
328 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
332 * Copy src to string dst of size siz. At most siz-1 characters
333 * will be copied. Always NUL terminates (unless siz == 0).
334 * Returns strlen(src); if retval >= siz, truncation occurred.
336 size_t
337 wstrlcpy(char *dst, const char *src, size_t siz)
339 char *d = dst;
340 const char *s = src;
341 size_t n = siz;
343 /* Copy as many bytes as will fit */
344 if (n != 0) {
345 while (--n != 0) {
346 if ((*d++ = *s++) == '\0')
347 break;
351 /* Not enough room in dst, add NUL and traverse rest of src */
352 if (n == 0) {
353 if (siz != 0)
354 *d = '\0'; /* NUL-terminate dst */
355 while (*s++)
359 return(s - src - 1); /* count does not include NUL */
361 #endif /* HAVE_STRLCPY */
363 /* transform `s' so that the result is safe to pass to the shell as an argument.
364 * returns a newly allocated string.
365 * with very heavy inspirations from NetBSD's shquote(3).
367 char *wshellquote(const char *s)
369 char *p, *r, *last, *ret;
370 size_t slen;
371 int needs_quoting;
373 if (!s)
374 return NULL;
376 needs_quoting = !*s; /* the empty string does need quoting */
378 /* do not quote if consists only of the following characters */
379 for (p = (char *)s; *p && !needs_quoting; p++) {
380 needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
381 (*p == '.') || (*p == ',') || (*p == '-'));
384 if (!needs_quoting)
385 return wstrdup(s);
387 for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
388 slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
390 slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
392 ret = r = wmalloc(slen);
393 p = (char *)s;
394 last = p;
396 if (*p != '\'') /* if string doesn't already begin with "'" */
397 *r++ ='\''; /* start putting it in quotes */
399 while (*p) {
400 last = p;
401 if (*p == '\'') { /* turn each ' into ''\' */
402 if (p != s) /* except if it's the first ', in which case */
403 *r++ = '\''; /* only escape it */
404 *r++ = '\\';
405 *r++ = '\'';
406 while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
407 *r++ = '\\';
408 *r++ = '\'';
410 if (*p) /* if more input follows, terminate */
411 *r++ = '\''; /* what we have so far */
412 } else {
413 *r++ = *p++;
417 if (*last != '\'') /* if the last one isn't already a ' */
418 *r++ = '\''; /* terminate the whole shebang */
420 *r = '\0';
422 return ret; /* technically, we lose (but not leak) a couple of */
423 /* bytes (twice the number of consecutive 's in the */
424 /* input or so), but since these are relatively rare */
425 /* and short-lived strings, not sure if a trip to */
426 /* wstrdup+wfree worths the gain. */