make switchpanel configurable
[wmaker-crm.git] / WINGs / string.c
bloba48d8d7fbec2b34db6371b2c850eec280b2e5ca5
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(**argv));
107 else
108 *argv = wrealloc(*argv, (count + 1) * sizeof(**argv));
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 strcat(dst, src);
240 return dst;
244 #ifdef 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 #ifdef 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. */