aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_str.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_str.c')
-rw-r--r--libraries/eina/src/lib/eina_str.c462
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 */
51static inline Eina_Bool
52eina_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
68static inline char **
69eina_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
180EAPI size_t
181eina_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
212EAPI size_t
213eina_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
243EAPI Eina_Bool
244eina_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
257EAPI Eina_Bool
258eina_str_has_suffix(const char *str, const char *suffix)
259{
260 return eina_str_has_suffix_helper(str, suffix, strcmp);
261}
262
263EAPI Eina_Bool
264eina_str_has_extension(const char *str, const char *ext)
265{
266 return eina_str_has_suffix_helper(str, ext, strcasecmp);
267}
268
269EAPI char **
270eina_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
279EAPI char **
280eina_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
285EAPI size_t
286eina_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
332EAPI char *
333eina_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
409EAPI char *
410eina_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
418EAPI char *
419eina_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
442EAPI void
443eina_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
453EAPI void
454eina_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}