Update Serbian translation from master branch
[wmaker-crm.git] / WINGs / string.c
blob393f28870a21d3202f114a30095eb4d4ddeee3a3
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, slen1;
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 slen1 = strlen(str1);
217 slen = slen1 + strlen(str2) + 1;
218 str = wmalloc(slen);
219 strcpy(str, str1);
220 strcpy(str + slen1, str2);
222 return str;
225 char *wstrappend(char *dst, const char *src)
227 size_t slen;
229 if (!src || *src == 0)
230 return dst;
231 else if (!dst)
232 return wstrdup(src);
234 slen = strlen(dst) + strlen(src) + 1;
235 dst = wrealloc(dst, slen);
236 strcat(dst, src);
238 return dst;
242 #ifdef HAVE_STRLCAT
243 size_t
244 wstrlcat(char *dst, const char *src, size_t siz)
246 return strlcat(dst, src, siz);
248 #else
249 /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
252 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
254 * Permission to use, copy, modify, and distribute this software for any
255 * purpose with or without fee is hereby granted, provided that the above
256 * copyright notice and this permission notice appear in all copies.
258 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
259 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
260 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
261 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
262 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
263 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
264 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
268 * Appends src to string dst of size siz (unlike strncat, siz is the
269 * full size of dst, not space left). At most siz-1 characters
270 * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
271 * Returns strlen(src) + MIN(siz, strlen(initial dst)).
272 * If retval >= siz, truncation occurred.
274 size_t
275 wstrlcat(char *dst, const char *src, size_t siz)
277 char *d = dst;
278 const char *s = src;
279 size_t n = siz;
280 size_t dlen;
282 /* Find the end of dst and adjust bytes left but don't go past end */
283 while (n-- != 0 && *d != '\0')
284 d++;
285 dlen = d - dst;
286 n = siz - dlen;
288 if (n == 0)
289 return(dlen + strlen(s));
290 while (*s != '\0') {
291 if (n != 1) {
292 *d++ = *s;
293 n--;
295 s++;
297 *d = '\0';
299 return(dlen + (s - src)); /* count does not include NUL */
301 #endif /* HAVE_STRLCAT */
303 #ifdef HAVE_STRLCPY
304 size_t
305 wstrlcpy(char *dst, const char *src, size_t siz)
307 return strlcpy(dst, src, siz);
309 #else
311 /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
314 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
316 * Permission to use, copy, modify, and distribute this software for any
317 * purpose with or without fee is hereby granted, provided that the above
318 * copyright notice and this permission notice appear in all copies.
320 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
321 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
322 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
323 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
324 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
325 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
326 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
330 * Copy src to string dst of size siz. At most siz-1 characters
331 * will be copied. Always NUL terminates (unless siz == 0).
332 * Returns strlen(src); if retval >= siz, truncation occurred.
334 size_t
335 wstrlcpy(char *dst, const char *src, size_t siz)
337 char *d = dst;
338 const char *s = src;
339 size_t n = siz;
341 /* Copy as many bytes as will fit */
342 if (n != 0) {
343 while (--n != 0) {
344 if ((*d++ = *s++) == '\0')
345 break;
349 /* Not enough room in dst, add NUL and traverse rest of src */
350 if (n == 0) {
351 if (siz != 0)
352 *d = '\0'; /* NUL-terminate dst */
353 while (*s++)
357 return(s - src - 1); /* count does not include NUL */
359 #endif /* HAVE_STRLCPY */
361 /* transform `s' so that the result is safe to pass to the shell as an argument.
362 * returns a newly allocated string.
363 * with very heavy inspirations from NetBSD's shquote(3).
365 char *wshellquote(const char *s)
367 char *p, *r, *last, *ret;
368 size_t slen;
369 int needs_quoting;
371 if (!s)
372 return NULL;
374 needs_quoting = !*s; /* the empty string does need quoting */
376 /* do not quote if consists only of the following characters */
377 for (p = (char *)s; *p && !needs_quoting; p++) {
378 needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
379 (*p == '.') || (*p == ',') || (*p == '-'));
382 if (!needs_quoting)
383 return wstrdup(s);
385 for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
386 slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
388 slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
390 ret = r = wmalloc(slen);
391 p = (char *)s;
392 last = p;
394 if (*p != '\'') /* if string doesn't already begin with "'" */
395 *r++ ='\''; /* start putting it in quotes */
397 while (*p) {
398 last = p;
399 if (*p == '\'') { /* turn each ' into ''\' */
400 if (p != s) /* except if it's the first ', in which case */
401 *r++ = '\''; /* only escape it */
402 *r++ = '\\';
403 *r++ = '\'';
404 while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
405 *r++ = '\\';
406 *r++ = '\'';
408 if (*p) /* if more input follows, terminate */
409 *r++ = '\''; /* what we have so far */
410 } else {
411 *r++ = *p++;
415 if (*last != '\'') /* if the last one isn't already a ' */
416 *r++ = '\''; /* terminate the whole shebang */
418 *r = '\0';
420 return ret; /* technically, we lose (but not leak) a couple of */
421 /* bytes (twice the number of consecutive 's in the */
422 /* input or so), but since these are relatively rare */
423 /* and short-lived strings, not sure if a trip to */
424 /* wstrdup+wfree worths the gain. */