Icon creation in only one function
[wmaker-crm.git] / WINGs / string.c
blob8da008fc18bb9a90b97c54371246945bdb90c1cf
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 t = NULL;
83 else
84 t = wstrdup(ret);
86 wfree(ret);
88 if (ctype == PRC_EOS)
89 *next = NULL;
90 else
91 *next = ptr;
93 return t;
96 /* separate a string in tokens, taking " and ' into account */
97 void wtokensplit(char *command, char ***argv, int *argc)
99 char *token, *line;
100 int count;
102 count = 0;
103 line = command;
104 do {
105 token = wtokennext(line, &line);
106 if (token) {
107 if (count == 0)
108 *argv = wmalloc(sizeof(char **));
109 else
110 *argv = wrealloc(*argv, (count + 1) * sizeof(char **));
111 (*argv)[count++] = token;
113 } while (token != NULL && line != NULL);
115 *argc = count;
118 char *wtokenjoin(char **list, int count)
120 int i, j;
121 char *flat_string, *wspace;
123 j = 0;
124 for (i = 0; i < count; i++) {
125 if (list[i] != NULL && list[i][0] != 0) {
126 j += strlen(list[i]);
127 if (strpbrk(list[i], " \t"))
128 j += 2;
132 flat_string = wmalloc(j + count + 1);
134 for (i = 0; i < count; i++) {
135 if (list[i] != NULL && list[i][0] != 0) {
136 if (i > 0 &&
137 wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
138 goto error;
140 wspace = strpbrk(list[i], " \t");
142 if (wspace &&
143 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
144 goto error;
146 if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
147 goto error;
149 if (wspace &&
150 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
151 goto error;
155 return flat_string;
157 error:
158 wfree(flat_string);
160 return NULL;
163 void wtokenfree(char **tokens, int count)
165 while (count--)
166 wfree(tokens[count]);
167 wfree(tokens);
170 char *wtrimspace(const char *s)
172 char *t;
174 if (s == NULL)
175 return NULL;
177 while (isspace(*s) && *s)
178 s++;
179 t = (char *)s + strlen(s) - 1;
180 while (t > s && isspace(*t))
181 t--;
183 return wstrndup(s, t - s + 1);
186 char *wstrdup(const char *str)
188 assert(str != NULL);
190 return strcpy(wmalloc(strlen(str) + 1), str);
193 char *wstrndup(const char *str, size_t len)
195 char *copy;
197 assert(str != NULL);
199 len = WMIN(len, strlen(str));
200 copy = strncpy(wmalloc(len + 1), str, len);
201 copy[len] = 0;
203 return copy;
206 char *wstrconcat(char *str1, char *str2)
208 char *str;
209 size_t slen;
211 if (!str1 && str2)
212 return wstrdup(str2);
213 else if (str1 && !str2)
214 return wstrdup(str1);
215 else if (!str1 && !str2)
216 return NULL;
218 slen = strlen(str1) + strlen(str2) + 1;
219 str = wmalloc(slen);
220 if (wstrlcpy(str, str1, slen) >= slen ||
221 wstrlcat(str, str2, slen) >= slen) {
222 wfree(str);
223 return NULL;
226 return str;
229 char *wstrappend(char *dst, char *src)
231 size_t slen;
233 if (!src || *src == 0)
234 return dst;
235 else if (!dst)
236 return wstrdup(src);
238 slen = strlen(dst) + strlen(src) + 1;
239 dst = wrealloc(dst, slen);
240 if (wstrlcat(dst, src, slen) >= slen)
241 return NULL;
243 return dst;
247 #if HAVE_STRLCAT
248 size_t
249 wstrlcat(char *dst, const char *src, size_t siz)
251 return strlcat(dst, src, siz);
253 #else
254 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
257 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
259 * Permission to use, copy, modify, and distribute this software for any
260 * purpose with or without fee is hereby granted, provided that the above
261 * copyright notice and this permission notice appear in all copies.
263 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
264 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
265 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
266 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
267 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
268 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
269 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
273 * Appends src to string dst of size siz (unlike strncat, siz is the
274 * full size of dst, not space left). At most siz-1 characters
275 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
276 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
277 * If retval >= siz, truncation occurred.
279 size_t
280 wstrlcat(char *dst, const char *src, size_t siz)
282 char *d = dst;
283 const char *s = src;
284 size_t n = siz;
285 size_t dlen;
287 /* Find the end of dst and adjust bytes left but don't go past end */
288 while (n-- != 0 && *d != '\0')
289 d++;
290 dlen = d - dst;
291 n = siz - dlen;
293 if (n == 0)
294 return(dlen + strlen(s));
295 while (*s != '\0') {
296 if (n != 1) {
297 *d++ = *s;
298 n--;
300 s++;
302 *d = '\0';
304 return(dlen + (s - src)); /* count does not include NUL */
306 #endif /* HAVE_STRLCAT */
308 #if HAVE_STRLCPY
309 size_t
310 wstrlcpy(char *dst, const char *src, size_t siz)
312 return strlcpy(dst, src, siz);
314 #else
316 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
319 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
321 * Permission to use, copy, modify, and distribute this software for any
322 * purpose with or without fee is hereby granted, provided that the above
323 * copyright notice and this permission notice appear in all copies.
325 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
326 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
327 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
328 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
329 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
330 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
331 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
335 * Copy src to string dst of size siz. At most siz-1 characters
336 * will be copied. Always NUL terminates (unless siz == 0).
337 * Returns strlen(src); if retval >= siz, truncation occurred.
339 size_t
340 wstrlcpy(char *dst, const char *src, size_t siz)
342 char *d = dst;
343 const char *s = src;
344 size_t n = siz;
346 /* Copy as many bytes as will fit */
347 if (n != 0) {
348 while (--n != 0) {
349 if ((*d++ = *s++) == '\0')
350 break;
354 /* Not enough room in dst, add NUL and traverse rest of src */
355 if (n == 0) {
356 if (siz != 0)
357 *d = '\0'; /* NUL-terminate dst */
358 while (*s++)
362 return(s - src - 1); /* count does not include NUL */
364 #endif /* HAVE_STRLCPY */
366 /* transform `s' so that the result is safe to pass to the shell as an argument.
367 * returns a newly allocated string.
368 * with very heavy inspirations from NetBSD's shquote(3).
370 char *wshellquote(const char *s)
372 char *p, *r, *last, *ret;
373 size_t slen;
374 int needs_quoting;
376 if (!s)
377 return NULL;
379 needs_quoting = !*s; /* the empty string does need quoting */
381 /* do not quote if consists only of the following characters */
382 for (p = (char *)s; *p && !needs_quoting; p++) {
383 needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
384 (*p == '.') || (*p == ',') || (*p == '-'));
387 if (!needs_quoting)
388 return wstrdup(s);
390 for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
391 slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
393 slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
395 ret = r = wmalloc(slen);
396 p = (char *)s;
397 last = p;
399 if (*p != '\'') /* if string doesn't already begin with "'" */
400 *r++ ='\''; /* start putting it in quotes */
402 while (*p) {
403 last = p;
404 if (*p == '\'') { /* turn each ' into ''\' */
405 if (p != s) /* except if it's the first ', in which case */
406 *r++ = '\''; /* only escape it */
407 *r++ = '\\';
408 *r++ = '\'';
409 while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
410 *r++ = '\\';
411 *r++ = '\'';
413 if (*p) /* if more input follows, terminate */
414 *r++ = '\''; /* what we have so far */
415 } else {
416 *r++ = *p++;
420 if (*last != '\'') /* if the last one isn't already a ' */
421 *r++ = '\''; /* terminate the whole shebang */
423 *r = '\0';
425 return ret; /* technically, we lose (but not leak) a couple of */
426 /* bytes (twice the number of consecutive 's in the */
427 /* input or so), but since these are relatively rare */
428 /* and short-lived strings, not sure if a trip to */
429 /* wstrdup+wfree worths the gain. */