wmgenmenu: Add French and Spanish translations
[wmaker-crm.git] / WINGs / string.c
blobc51a0f14780e7a8245544ff391c4ba9d3da7d659
2 #include "wconfig.h"
4 #include <string.h>
5 #include <stdlib.h>
6 #include <ctype.h>
7 #ifdef HAVE_BSD_STRING_H
8 #include <bsd/string.h>
9 #endif
11 #include "WUtil.h"
13 #define PRC_ALPHA 0
14 #define PRC_BLANK 1
15 #define PRC_ESCAPE 2
16 #define PRC_DQUOTE 3
17 #define PRC_EOS 4
18 #define PRC_SQUOTE 5
20 typedef struct {
21 short nstate;
22 short output;
23 } DFA;
25 static DFA mtable[9][6] = {
26 {{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
27 {{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
28 {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
29 {{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
30 {{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
31 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
32 {{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
33 {{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
34 {{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
37 char *wtokennext(char *word, char **next)
39 char *ptr;
40 char *ret, *t;
41 int state, ctype;
43 t = ret = wmalloc(strlen(word) + 1);
44 ptr = word;
46 state = 0;
47 while (1) {
48 if (*ptr == 0)
49 ctype = PRC_EOS;
50 else if (*ptr == '\\')
51 ctype = PRC_ESCAPE;
52 else if (*ptr == '"')
53 ctype = PRC_DQUOTE;
54 else if (*ptr == '\'')
55 ctype = PRC_SQUOTE;
56 else if (*ptr == ' ' || *ptr == '\t')
57 ctype = PRC_BLANK;
58 else
59 ctype = PRC_ALPHA;
61 if (mtable[state][ctype].output) {
62 *t = *ptr;
63 t++;
64 *t = 0;
66 state = mtable[state][ctype].nstate;
67 ptr++;
68 if (mtable[state][0].output < 0) {
69 break;
73 if (*ret == 0)
74 t = NULL;
75 else
76 t = wstrdup(ret);
78 wfree(ret);
80 if (ctype == PRC_EOS)
81 *next = NULL;
82 else
83 *next = ptr;
85 return t;
88 /* separate a string in tokens, taking " and ' into account */
89 void wtokensplit(char *command, char ***argv, int *argc)
91 char *token, *line;
92 int count;
94 count = 0;
95 line = command;
96 do {
97 token = wtokennext(line, &line);
98 if (token) {
99 if (count == 0)
100 *argv = wmalloc(sizeof(char **));
101 else
102 *argv = wrealloc(*argv, (count + 1) * sizeof(char **));
103 (*argv)[count++] = token;
105 } while (token != NULL && line != NULL);
107 *argc = count;
110 char *wtokenjoin(char **list, int count)
112 int i, j;
113 char *flat_string, *wspace;
115 j = 0;
116 for (i = 0; i < count; i++) {
117 if (list[i] != NULL && list[i][0] != 0) {
118 j += strlen(list[i]);
119 if (strpbrk(list[i], " \t"))
120 j += 2;
124 flat_string = wmalloc(j + count + 1);
126 for (i = 0; i < count; i++) {
127 if (list[i] != NULL && list[i][0] != 0) {
128 if (i > 0 &&
129 wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
130 goto error;
132 wspace = strpbrk(list[i], " \t");
134 if (wspace &&
135 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
136 goto error;
138 if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
139 goto error;
141 if (wspace &&
142 wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
143 goto error;
147 return flat_string;
149 error:
150 wfree(flat_string);
152 return NULL;
155 void wtokenfree(char **tokens, int count)
157 while (count--)
158 wfree(tokens[count]);
159 wfree(tokens);
162 char *wtrimspace(const char *s)
164 char *t;
166 if (s == NULL)
167 return NULL;
169 while (isspace(*s) && *s)
170 s++;
171 t = (char *)s + strlen(s) - 1;
172 while (t > s && isspace(*t))
173 t--;
175 return wstrndup(s, t - s + 1);
178 char *wstrdup(const char *str)
180 assert(str != NULL);
182 return strcpy(wmalloc(strlen(str) + 1), str);
185 char *wstrndup(const char *str, size_t len)
187 char *copy;
189 assert(str != NULL);
191 len = WMIN(len, strlen(str));
192 copy = strncpy(wmalloc(len + 1), str, len);
193 copy[len] = 0;
195 return copy;
198 char *wstrconcat(char *str1, char *str2)
200 char *str;
201 size_t slen;
203 if (!str1)
204 return wstrdup(str2);
205 else if (!str2)
206 return wstrdup(str1);
208 slen = strlen(str1) + strlen(str2) + 1;
209 str = wmalloc(slen);
210 if (wstrlcpy(str, str1, slen) >= slen ||
211 wstrlcat(str, str2, slen) >= slen) {
212 wfree(str);
213 return NULL;
216 return str;
219 char *wstrappend(char *dst, char *src)
221 size_t slen;
223 if (!dst)
224 return wstrdup(src);
225 else if (!src || *src == 0)
226 return dst;
228 slen = strlen(dst) + strlen(src) + 1;
229 dst = wrealloc(dst, slen);
230 if (wstrlcat(dst, src, slen) >= slen)
231 return NULL;
233 return dst;
237 #ifdef HAVE_STRLCAT
238 size_t
239 wstrlcat(char *dst, const char *src, size_t siz)
241 return strlcat(dst, src, siz);
243 #else
244 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
247 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
249 * Permission to use, copy, modify, and distribute this software for any
250 * purpose with or without fee is hereby granted, provided that the above
251 * copyright notice and this permission notice appear in all copies.
253 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
254 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
255 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
256 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
257 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
258 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
259 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
263 * Appends src to string dst of size siz (unlike strncat, siz is the
264 * full size of dst, not space left). At most siz-1 characters
265 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
266 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
267 * If retval >= siz, truncation occurred.
269 size_t
270 wstrlcat(char *dst, const char *src, size_t siz)
272 char *d = dst;
273 const char *s = src;
274 size_t n = siz;
275 size_t dlen;
277 /* Find the end of dst and adjust bytes left but don't go past end */
278 while (n-- != 0 && *d != '\0')
279 d++;
280 dlen = d - dst;
281 n = siz - dlen;
283 if (n == 0)
284 return(dlen + strlen(s));
285 while (*s != '\0') {
286 if (n != 1) {
287 *d++ = *s;
288 n--;
290 s++;
292 *d = '\0';
294 return(dlen + (s - src)); /* count does not include NUL */
296 #endif /* HAVE_STRLCAT */
298 #ifdef HAVE_STRLCPY
299 size_t
300 wstrlcpy(char *dst, const char *src, size_t siz)
302 return strlcpy(dst, src, siz);
304 #else
306 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
309 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
311 * Permission to use, copy, modify, and distribute this software for any
312 * purpose with or without fee is hereby granted, provided that the above
313 * copyright notice and this permission notice appear in all copies.
315 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
316 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
317 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
318 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
319 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
320 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
321 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
325 * Copy src to string dst of size siz. At most siz-1 characters
326 * will be copied. Always NUL terminates (unless siz == 0).
327 * Returns strlen(src); if retval >= siz, truncation occurred.
329 size_t
330 wstrlcpy(char *dst, const char *src, size_t siz)
332 char *d = dst;
333 const char *s = src;
334 size_t n = siz;
336 /* Copy as many bytes as will fit */
337 if (n != 0) {
338 while (--n != 0) {
339 if ((*d++ = *s++) == '\0')
340 break;
344 /* Not enough room in dst, add NUL and traverse rest of src */
345 if (n == 0) {
346 if (siz != 0)
347 *d = '\0'; /* NUL-terminate dst */
348 while (*s++)
352 return(s - src - 1); /* count does not include NUL */
354 #endif /* HAVE_STRLCPY */
356 /* transform `s' so that the result is safe to pass to the shell as an argument.
357 * returns a newly allocated string.
358 * with very heavy inspirations from NetBSD's shquote(3).
360 char *wshellquote(const char *s)
362 char *p, *r, *last, *ret;
363 size_t slen;
364 int needs_quoting;
366 if (!s)
367 return NULL;
369 needs_quoting = !*s; /* the empty string does need quoting */
371 /* do not quote if consists only of the following characters */
372 for (p = (char *)s; *p && !needs_quoting; p++) {
373 needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
374 (*p == '.') || (*p == ',') || (*p == '-'));
377 if (!needs_quoting)
378 return wstrdup(s);
380 for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
381 slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
383 slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
385 ret = r = wmalloc(slen);
386 p = (char *)s;
387 last = p;
389 if (*p != '\'') /* if string doesn't already begin with "'" */
390 *r++ ='\''; /* start putting it in quotes */
392 while (*p) {
393 last = p;
394 if (*p == '\'') { /* turn each ' into ''\' */
395 if (p != s) /* except if it's the first ', in which case */
396 *r++ = '\''; /* only escape it */
397 *r++ = '\\';
398 *r++ = '\'';
399 while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
400 *r++ = '\\';
401 *r++ = '\'';
403 if (*p) /* if more input follows, terminate */
404 *r++ = '\''; /* what we have so far */
405 } else {
406 *r++ = *p++;
410 if (*last != '\'') /* if the last one isn't already a ' */
411 *r++ = '\''; /* terminate the whole shebang */
413 *r = '\0';
415 return ret; /* technically, we lose (but not leak) a couple of */
416 /* bytes (twice the number of consecutive 's in the */
417 /* input or so), but since these are relatively rare */
418 /* and short-lived strings, not sure if a trip to */
419 /* wstrdup+wfree worths the gain. */