diff options
Diffstat (limited to 'libraries/eina/src/lib/eina_str.c')
-rw-r--r-- | libraries/eina/src/lib/eina_str.c | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_str.c b/libraries/eina/src/lib/eina_str.c new file mode 100644 index 0000000..8d27c65 --- /dev/null +++ b/libraries/eina/src/lib/eina_str.c | |||
@@ -0,0 +1,462 @@ | |||
1 | /* Leave the OpenBSD version below so we can track upstream fixes */ | ||
2 | /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | */ | ||
19 | |||
20 | |||
21 | #ifdef HAVE_CONFIG_H | ||
22 | # include "config.h" | ||
23 | #endif | ||
24 | |||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <limits.h> | ||
29 | #include <ctype.h> | ||
30 | |||
31 | #ifdef HAVE_ICONV | ||
32 | # include <errno.h> | ||
33 | # include <iconv.h> | ||
34 | #endif | ||
35 | |||
36 | #include "eina_private.h" | ||
37 | #include "eina_str.h" | ||
38 | |||
39 | /*============================================================================* | ||
40 | * Local * | ||
41 | *============================================================================*/ | ||
42 | |||
43 | /** | ||
44 | * @cond LOCAL | ||
45 | */ | ||
46 | |||
47 | /* | ||
48 | * Internal helper function used by eina_str_has_suffix() and | ||
49 | * eina_str_has_extension() | ||
50 | */ | ||
51 | static inline Eina_Bool | ||
52 | eina_str_has_suffix_helper(const char *str, | ||
53 | const char *suffix, | ||
54 | int (*cmp)(const char *, const char *)) | ||
55 | { | ||
56 | size_t str_len; | ||
57 | size_t suffix_len; | ||
58 | |||
59 | if ((!str) || (!suffix)) return EINA_FALSE; | ||
60 | str_len = strlen(str); | ||
61 | suffix_len = eina_strlen_bounded(suffix, str_len); | ||
62 | if (suffix_len == (size_t)-1) | ||
63 | return EINA_FALSE; | ||
64 | |||
65 | return cmp(str + str_len - suffix_len, suffix) == 0; | ||
66 | } | ||
67 | |||
68 | static inline char ** | ||
69 | eina_str_split_full_helper(const char *str, | ||
70 | const char *delim, | ||
71 | int max_tokens, | ||
72 | unsigned int *elements) | ||
73 | { | ||
74 | char *s, **str_array; | ||
75 | const char *src; | ||
76 | size_t len, dlen; | ||
77 | unsigned int tokens; | ||
78 | |||
79 | dlen = strlen(delim); | ||
80 | if (dlen == 0) | ||
81 | { | ||
82 | if (elements) | ||
83 | *elements = 0; | ||
84 | |||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | tokens = 0; | ||
89 | src = str; | ||
90 | /* count tokens and check strlen(str) */ | ||
91 | while (*src != '\0') | ||
92 | { | ||
93 | const char *d = delim, *d_end = d + dlen; | ||
94 | const char *tmp = src; | ||
95 | for (; (d < d_end) && (*tmp != '\0'); d++, tmp++) | ||
96 | { | ||
97 | if (EINA_LIKELY(*d != *tmp)) | ||
98 | break; | ||
99 | } | ||
100 | if (EINA_UNLIKELY(d == d_end)) | ||
101 | { | ||
102 | src = tmp; | ||
103 | tokens++; | ||
104 | } | ||
105 | else | ||
106 | src++; | ||
107 | } | ||
108 | len = src - str; | ||
109 | |||
110 | if ((max_tokens > 0) && (tokens > (unsigned int)max_tokens)) | ||
111 | tokens = max_tokens; | ||
112 | |||
113 | str_array = malloc(sizeof(char *) * (tokens + 2)); | ||
114 | if (!str_array) | ||
115 | { | ||
116 | if (elements) | ||
117 | *elements = 0; | ||
118 | |||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | s = malloc(len + 1); | ||
123 | if (!s) | ||
124 | { | ||
125 | free(str_array); | ||
126 | if (elements) | ||
127 | *elements = 0; | ||
128 | |||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | /* copy tokens and string */ | ||
133 | tokens = 0; | ||
134 | str_array[0] = s; | ||
135 | src = str; | ||
136 | while (*src != '\0') | ||
137 | { | ||
138 | const char *d = delim, *d_end = d + dlen; | ||
139 | const char *tmp = src; | ||
140 | for (; (d < d_end) && (*tmp != '\0'); d++, tmp++) | ||
141 | { | ||
142 | if (EINA_LIKELY(*d != *tmp)) | ||
143 | break; | ||
144 | } | ||
145 | if (EINA_UNLIKELY(d == d_end)) | ||
146 | { | ||
147 | src = tmp; | ||
148 | *s = '\0'; | ||
149 | s += dlen; | ||
150 | tokens++; | ||
151 | str_array[tokens] = s; | ||
152 | } | ||
153 | else | ||
154 | { | ||
155 | *s = *src; | ||
156 | s++; | ||
157 | src++; | ||
158 | } | ||
159 | } | ||
160 | *s = '\0'; | ||
161 | str_array[tokens + 1] = NULL; | ||
162 | if (elements) | ||
163 | *elements = (tokens + 1); | ||
164 | |||
165 | return str_array; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * @endcond | ||
170 | */ | ||
171 | |||
172 | /*============================================================================* | ||
173 | * Global * | ||
174 | *============================================================================*/ | ||
175 | |||
176 | /*============================================================================* | ||
177 | * API * | ||
178 | *============================================================================*/ | ||
179 | |||
180 | EAPI size_t | ||
181 | eina_strlcpy(char *dst, const char *src, size_t siz) | ||
182 | { | ||
183 | #ifdef HAVE_STRLCPY | ||
184 | return strlcpy(dst, src, siz); | ||
185 | #else | ||
186 | char *d = dst; | ||
187 | const char *s = src; | ||
188 | size_t n = siz; | ||
189 | |||
190 | /* Copy as many bytes as will fit */ | ||
191 | if (n != 0) | ||
192 | while (--n != 0) | ||
193 | { | ||
194 | if ((*d++ = *s++) == '\0') | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | /* Not enough room in dst, add NUL and traverse rest of src */ | ||
199 | if (n == 0) | ||
200 | { | ||
201 | if (siz != 0) | ||
202 | *d = '\0'; /* NUL-terminate dst */ | ||
203 | |||
204 | while (*s++) | ||
205 | ; | ||
206 | } | ||
207 | |||
208 | return(s - src - 1); /* count does not include NUL */ | ||
209 | #endif | ||
210 | } | ||
211 | |||
212 | EAPI size_t | ||
213 | eina_strlcat(char *dst, const char *src, size_t siz) | ||
214 | { | ||
215 | char *d = dst; | ||
216 | const char *s = src; | ||
217 | size_t n = siz; | ||
218 | size_t dlen; | ||
219 | |||
220 | /* Find the end of dst and adjust bytes left but don't go past end */ | ||
221 | while (n-- != 0 && *d != '\0') | ||
222 | d++; | ||
223 | dlen = d - dst; | ||
224 | n = siz - dlen; | ||
225 | |||
226 | if (n == 0) | ||
227 | return(dlen + strlen(s)); | ||
228 | |||
229 | while (*s != '\0') { | ||
230 | if (n != 1) | ||
231 | { | ||
232 | *d++ = *s; | ||
233 | n--; | ||
234 | } | ||
235 | |||
236 | s++; | ||
237 | } | ||
238 | *d = '\0'; | ||
239 | |||
240 | return(dlen + (s - src)); /* count does not include NUL */ | ||
241 | } | ||
242 | |||
243 | EAPI Eina_Bool | ||
244 | eina_str_has_prefix(const char *str, const char *prefix) | ||
245 | { | ||
246 | size_t str_len; | ||
247 | size_t prefix_len; | ||
248 | |||
249 | str_len = strlen(str); | ||
250 | prefix_len = eina_strlen_bounded(prefix, str_len); | ||
251 | if (prefix_len == (size_t)-1) | ||
252 | return EINA_FALSE; | ||
253 | |||
254 | return (strncmp(str, prefix, prefix_len) == 0); | ||
255 | } | ||
256 | |||
257 | EAPI Eina_Bool | ||
258 | eina_str_has_suffix(const char *str, const char *suffix) | ||
259 | { | ||
260 | return eina_str_has_suffix_helper(str, suffix, strcmp); | ||
261 | } | ||
262 | |||
263 | EAPI Eina_Bool | ||
264 | eina_str_has_extension(const char *str, const char *ext) | ||
265 | { | ||
266 | return eina_str_has_suffix_helper(str, ext, strcasecmp); | ||
267 | } | ||
268 | |||
269 | EAPI char ** | ||
270 | eina_str_split_full(const char *str, | ||
271 | const char *delim, | ||
272 | int max_tokens, | ||
273 | unsigned int *elements) | ||
274 | { | ||
275 | return eina_str_split_full_helper(str, delim, max_tokens, elements); | ||
276 | } | ||
277 | |||
278 | |||
279 | EAPI char ** | ||
280 | eina_str_split(const char *str, const char *delim, int max_tokens) | ||
281 | { | ||
282 | return eina_str_split_full_helper(str, delim, max_tokens, NULL); | ||
283 | } | ||
284 | |||
285 | EAPI size_t | ||
286 | eina_str_join_len(char *dst, | ||
287 | size_t size, | ||
288 | char sep, | ||
289 | const char *a, | ||
290 | size_t a_len, | ||
291 | const char *b, | ||
292 | size_t b_len) | ||
293 | { | ||
294 | size_t ret = a_len + b_len + 1; | ||
295 | size_t off; | ||
296 | |||
297 | if (size < 1) | ||
298 | return ret; | ||
299 | |||
300 | if (size <= a_len) | ||
301 | { | ||
302 | memcpy(dst, a, size - 1); | ||
303 | dst[size - 1] = '\0'; | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | memcpy(dst, a, a_len); | ||
308 | off = a_len; | ||
309 | |||
310 | if (size <= off + 1) | ||
311 | { | ||
312 | dst[size - 1] = '\0'; | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | dst[off] = sep; | ||
317 | off++; | ||
318 | |||
319 | if (size <= off + b_len + 1) | ||
320 | { | ||
321 | memcpy(dst + off, b, size - off - 1); | ||
322 | dst[size - 1] = '\0'; | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | memcpy(dst + off, b, b_len); | ||
327 | dst[off + b_len] = '\0'; | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | #ifdef HAVE_ICONV | ||
332 | EAPI char * | ||
333 | eina_str_convert(const char *enc_from, const char *enc_to, const char *text) | ||
334 | { | ||
335 | iconv_t ic; | ||
336 | char *new_txt, *inp, *outp; | ||
337 | size_t inb, outb, outlen, tob, outalloc; | ||
338 | |||
339 | if (!text) | ||
340 | return NULL; | ||
341 | |||
342 | ic = iconv_open(enc_to, enc_from); | ||
343 | if (ic == (iconv_t)(-1)) | ||
344 | return NULL; | ||
345 | |||
346 | new_txt = malloc(64); | ||
347 | inb = strlen(text); | ||
348 | outb = 64; | ||
349 | inp = (char *)text; | ||
350 | outp = new_txt; | ||
351 | outalloc = 64; | ||
352 | outlen = 0; | ||
353 | |||
354 | for (;; ) | ||
355 | { | ||
356 | size_t count; | ||
357 | |||
358 | tob = outb; | ||
359 | count = iconv(ic, &inp, &inb, &outp, &outb); | ||
360 | outlen += tob - outb; | ||
361 | if (count == (size_t)(-1)) | ||
362 | { | ||
363 | if (errno == E2BIG) | ||
364 | { | ||
365 | new_txt = realloc(new_txt, outalloc + 64); | ||
366 | outp = new_txt + outlen; | ||
367 | outalloc += 64; | ||
368 | outb += 64; | ||
369 | } | ||
370 | else if (errno == EILSEQ) | ||
371 | { | ||
372 | if (new_txt) | ||
373 | free(new_txt); | ||
374 | |||
375 | new_txt = NULL; | ||
376 | break; | ||
377 | } | ||
378 | else if (errno == EINVAL) | ||
379 | { | ||
380 | if (new_txt) | ||
381 | free(new_txt); | ||
382 | |||
383 | new_txt = NULL; | ||
384 | break; | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | if (new_txt) | ||
389 | free(new_txt); | ||
390 | |||
391 | new_txt = NULL; | ||
392 | break; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (inb == 0) | ||
397 | { | ||
398 | if (outalloc == outlen) | ||
399 | new_txt = realloc(new_txt, outalloc + 1); | ||
400 | |||
401 | new_txt[outlen] = 0; | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | iconv_close(ic); | ||
406 | return new_txt; | ||
407 | } | ||
408 | #else | ||
409 | EAPI char * | ||
410 | eina_str_convert(const char *enc_from __UNUSED__, | ||
411 | const char *enc_to __UNUSED__, | ||
412 | const char *text __UNUSED__) | ||
413 | { | ||
414 | return NULL; | ||
415 | } | ||
416 | #endif | ||
417 | |||
418 | EAPI char * | ||
419 | eina_str_escape(const char *str) | ||
420 | { | ||
421 | char *s2, *d; | ||
422 | const char *s; | ||
423 | |||
424 | s2 = malloc((strlen(str) * 2) + 1); | ||
425 | if (!s2) | ||
426 | return NULL; | ||
427 | |||
428 | for (s = str, d = s2; *s != 0; s++, d++) | ||
429 | { | ||
430 | if ((*s == ' ') || (*s == '\\') || (*s == '\'')) | ||
431 | { | ||
432 | *d = '\\'; | ||
433 | d++; | ||
434 | } | ||
435 | |||
436 | *d = *s; | ||
437 | } | ||
438 | *d = 0; | ||
439 | return s2; | ||
440 | } | ||
441 | |||
442 | EAPI void | ||
443 | eina_str_tolower(char **str) | ||
444 | { | ||
445 | char *p; | ||
446 | if ((!str) || (!(*str))) | ||
447 | return; | ||
448 | |||
449 | for (p = *str; (*p); p++) | ||
450 | *p = tolower((unsigned char )(*p)); | ||
451 | } | ||
452 | |||
453 | EAPI void | ||
454 | eina_str_toupper(char **str) | ||
455 | { | ||
456 | char *p; | ||
457 | if ((!str) || (!(*str))) | ||
458 | return; | ||
459 | |||
460 | for (p = *str; (*p); p++) | ||
461 | *p = toupper((unsigned char)(*p)); | ||
462 | } | ||