* fix compilation when iconv.h is detected but libiconv is not
[framework/uifw/eina.git] / src / lib / eina_str.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 /* Leave the OpenBSD version below so we can track upstream fixes */
5 /*      $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $        */
6
7 /*
8  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
9  *
10  * Permission to use, copy, modify, and distribute this software for any
11  * purpose with or without fee is hereby granted, provided that the above
12  * copyright notice and this permission notice appear in all copies.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 /*
24  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
34
35 #ifdef HAVE_ICONV
36 # include <errno.h>
37 # include <iconv.h>
38 #endif
39
40 #include "eina_private.h"
41 #include "eina_str.h"
42
43 /*============================================================================*
44  *                                  Local                                     *
45  *============================================================================*/
46
47 /**
48  * @cond LOCAL
49  */
50
51 /*
52  * Internal helper function used by eina_str_has_suffix() and
53  * eina_str_has_extension()
54  */
55 static Eina_Bool
56 eina_str_has_suffix_helper(const char *str,
57                            const char *suffix,
58                            int (*cmp)(const char *, const char *))
59 {
60    size_t str_len;
61    size_t suffix_len;
62
63    str_len = strlen(str);
64    suffix_len = strlen(suffix);
65    if (suffix_len > str_len)
66      return EINA_FALSE;
67
68    return cmp(str + str_len - suffix_len, suffix) == 0;
69 }
70
71 /**
72  * @endcond
73  */
74
75 /*============================================================================*
76  *                                 Global                                     *
77  *============================================================================*/
78
79 /*============================================================================*
80  *                                   API                                      *
81  *============================================================================*/
82
83
84 /**
85  * @brief Copy a c-string to another.
86  *
87  * @param dst The destination string.
88  * @param src The source string.
89  * @param siz The size of the destination string.
90  * @return The length of the source string.
91  *
92  * This function copies up to @p siz - 1 characters from the
93  * NUL-terminated string @p src to @p dst, NUL-terminating the result
94  * (unless @p siz is equal to 0). The returned value is the length of
95  * @p src. If the returned value is greater than @p siz, truncation
96  * occured.
97  */
98 EAPI size_t
99 eina_strlcpy(char *dst, const char *src, size_t siz)
100 {
101 #ifdef HAVE_STRLCPY
102    return strlcpy(dst, src, siz);
103 #else
104    char *d = dst;
105    const char *s = src;
106    size_t n = siz;
107
108    /* Copy as many bytes as will fit */
109    if (n != 0)
110      {
111         while (--n != 0)
112           {
113              if ((*d++ = *s++) == '\0')
114                break;
115           }
116      }
117
118    /* Not enough room in dst, add NUL and traverse rest of src */
119    if (n == 0)
120      {
121         if (siz != 0)
122           *d = '\0';                /* NUL-terminate dst */
123         while (*s++)
124           ;
125      }
126
127    return(s - src - 1);        /* count does not include NUL */
128 #endif
129 }
130
131 /**
132  * @brief Append a c-string.
133  *
134  * @param dst The destination string.
135  * @param src The source string.
136  * @param siz The size of the destination string.
137  * @return The length of the source string plus MIN(siz, strlen(initial dst))
138  *
139  * This function appends @p src to @p dst of size @p siz (unlike
140  * strncat, @p siz is the full size of @p dst, not space left).  At
141  * most @p siz - 1 characters will be copied.  Always NUL terminates
142  * (unless @p siz <= strlen(dst)). This function returns strlen(src) +
143  * MIN(siz, strlen(initial dst)). If the returned value is greater or
144  * equal than @p siz, truncation occurred.
145  */
146 EAPI size_t
147 eina_strlcat(char *dst, const char *src, size_t siz)
148 {
149    char *d = dst;
150    const char *s = src;
151    size_t n = siz;
152    size_t dlen;
153
154    /* Find the end of dst and adjust bytes left but don't go past end */
155    while (n-- != 0 && *d != '\0')
156      d++;
157    dlen = d - dst;
158    n = siz - dlen;
159
160    if (n == 0)
161      return(dlen + strlen(s));
162    while (*s != '\0') {
163         if (n != 1) {
164              *d++ = *s;
165              n--;
166         }
167         s++;
168    }
169    *d = '\0';
170
171    return(dlen + (s - src));        /* count does not include NUL */
172 }
173
174 /**
175  * @brief Check if the given string has the given prefix.
176  *
177  * @param str The string to work with.
178  * @param prefix The prefix to check for.
179  * @return #EINA_TRUE if the string has the given prefix, #EINA_FALSE otherwise.
180  *
181  * This function returns #EINA_TRUE if @p str has the prefix
182  * @p prefix, #EINA_FALSE otherwise. If the length of @p prefix is
183  * greater than @p str, #EINA_FALSE is returned.
184  */
185 EAPI Eina_Bool
186 eina_str_has_prefix(const char *str, const char *prefix)
187 {
188    size_t str_len;
189    size_t prefix_len;
190
191    str_len = strlen(str);
192    prefix_len = strlen(prefix);
193    if (prefix_len > str_len)
194      return EINA_FALSE;
195
196    return (strncmp(str, prefix, prefix_len) == 0);
197 }
198
199 /**
200  * @brief Check if the given string has the given suffix.
201  *
202  * @param str The string to work with.
203  * @param suffix The suffix to check for.
204  * @return #EINA_TRUE if the string has the given suffix, #EINA_FALSE otherwise.
205  *
206  * This function returns #EINA_TRUE if @p str has the suffix
207  * @p suffix, #EINA_FALSE otherwise. If the length of @p suffix is
208  * greater than @p str, #EINA_FALSE is returned.
209  */
210 /**
211  * @param str the string to work with
212  * @param suffix the suffix to check for
213  * @return true if str has the given suffix
214  * @brief checks if the string has the given suffix
215  */
216 EAPI Eina_Bool
217 eina_str_has_suffix(const char *str, const char *suffix)
218 {
219    return eina_str_has_suffix_helper(str, suffix, strcmp);
220 }
221
222 /**
223  * @brief Check if the given string has the given suffix.
224  *
225  * @param str The string to work with.
226  * @param ext The  extension to check for.
227  * @return #EINA_TRUE if the string has the given extension, #EINA_FALSE otherwise.
228  *
229  * This function does the same like eina_str_has_suffix(), but with a
230  * case insensitive compare.
231  */
232 EAPI Eina_Bool
233 eina_str_has_extension(const char *str, const char *ext)
234 {
235    return eina_str_has_suffix_helper(str, ext, strcasecmp);
236 }
237
238 /**
239  * @brief Split a string using a delimiter.
240  *
241  * @param str The string to split.
242  * @param delim The string which specifies the places at which to split the string.
243  * @param max_tokens The maximum number of strings to split string into.
244  * @return A newly-allocated NULL-terminated array of strings.
245  *
246  * This functin splits @p str into a maximum of @p max_tokens pieces,
247  * using the given delimiter @p delim. @p delim is not included in any
248  * of the resulting strings, unless @p max_tokens is reached. If
249  * @p max_tokens is less than @c 1, the string is splitted completely. If
250  * @p max_tokens is reached, the last string in the returned string
251  * array contains the remainder of string. The returned value is a
252  * newly allocated NUL-terminated array of string. To free it, free
253  * the first element of the array and the array itself.
254  */
255 EAPI char **
256 eina_str_split(const char *str, const char *delim, int max_tokens)
257 {
258    char *s, *sep, **str_array;
259    size_t len, dlen;
260    int i;
261
262    if (*delim == '\0')
263      return NULL;
264
265    max_tokens = ((max_tokens <= 0) ? (INT_MAX) : (max_tokens - 1));
266    len = strlen(str);
267    dlen = strlen(delim);
268    s = strdup(str);
269    str_array = malloc(sizeof(char *) * (len + 1));
270    for (i = 0; (i < max_tokens) && (sep = strstr(s, delim)); i++)
271      {
272         str_array[i] = s;
273         s = sep + dlen;
274         *sep = 0;
275      }
276
277    str_array[i++] = s;
278    str_array = realloc(str_array, sizeof(char *) * (i + 1));
279    str_array[i] = NULL;
280
281    return str_array;
282 }
283
284 /**
285  * @brief Join two strings of known length.
286  *
287  * @param dst The buffer to store the result.
288  * @param size Size (in byte) of the buffer.
289  * @param sep The separator character to use.
290  * @param a First string to use, before @p sep.
291  * @param a_len length of @p a.
292  * @param b Second string to use, after @p sep.
293  * @param b_len length of @p b.
294  * @return The number of characters printed.
295  *
296  * This function joins the strings @p a and @p b (in that order) and
297  * separate them with @p sep. The result is stored in the buffer
298  * @p dst and at most @p size - 1 characters will be written and the
299  * string is NULL-terminated. @p a_len is the length of @p a (not
300  * including '\0') and @p b_len is the length of @p b (not including
301  * '\0'). This function returns the number of characters printed (not
302  * including the trailing '\0' used to end output to strings). Just
303  * like snprintf(), it will not write more than @p size bytes, thus a
304  * returned value of @p size or more means that the output was
305  * truncated.
306  *
307  * @see eina_str_join()
308  * @see eina_str_join_static()
309  */
310 EAPI size_t
311 eina_str_join_len(char *dst, size_t size, char sep, const char *a, size_t a_len, const char *b, size_t b_len)
312 {
313    size_t ret = a_len + b_len + 1;
314    size_t off;
315
316    if (size < 1) return ret;
317
318    if (size <= a_len)
319      {
320         memcpy(dst, a, size - 1);
321         dst[size - 1] = '\0';
322         return ret;
323      }
324
325    memcpy(dst, a, a_len);
326    off = a_len;
327
328    if (size <= off + 1)
329      {
330         dst[size - 1] = '\0';
331         return ret;
332      }
333
334    dst[off] = sep;
335    off++;
336
337    if (size <= off + b_len + 1)
338      {
339         memcpy(dst + off, b, size - off - 1);
340         dst[size - 1] = '\0';
341         return ret;
342      }
343
344    memcpy(dst + off, b, b_len);
345    dst[off + b_len] = '\0';
346    return ret;
347 }
348
349 /**
350  * @brief Use iconv to convert a text string from one encoding to another
351  *
352  * @param enc_from encoding to convert from
353  * @param enc_to   encoding to convert to
354  * @param text     text to convert
355  *
356  */
357 #ifdef HAVE_ICONV
358 EAPI char *
359 eina_str_convert(const char *enc_from, const char *enc_to, const char *text)
360 {
361    iconv_t ic;
362    char *new_txt, *inp, *outp;
363    size_t inb, outb, outlen, tob, outalloc;
364    
365    if (!text) return NULL;
366    ic = iconv_open(enc_to, enc_from);
367    if (ic == (iconv_t)(-1)) return NULL;
368    new_txt  = malloc(64);
369    inb      = strlen(text);
370    outb     = 64;
371    inp      = (char*)text;
372    outp     = new_txt;
373    outalloc = 64;
374    outlen   = 0;
375
376    for (;;)
377      {
378         size_t count;
379
380         tob = outb;
381         count = iconv(ic, &inp, &inb, &outp, &outb);
382         outlen += tob - outb;
383         if (count == (size_t)(-1))
384           {
385              if (errno == E2BIG)
386                {
387                   new_txt = realloc(new_txt, outalloc + 64);
388                   outp = new_txt + outlen;
389                   outalloc += 64;
390                   outb += 64;
391                }
392              else if (errno == EILSEQ)
393                {
394                   if (new_txt) free(new_txt);
395                   new_txt = NULL;
396                   break;
397                }
398              else if (errno == EINVAL)
399                {
400                   if (new_txt) free(new_txt);
401                   new_txt = NULL;
402                   break;
403                }
404              else
405                {
406                   if (new_txt) free(new_txt);
407                   new_txt = NULL;
408                   break;
409                }
410           }
411         if (inb == 0)
412           {
413              if (outalloc == outlen) new_txt = realloc(new_txt, outalloc + 1);
414              new_txt[outlen] = 0;
415              break;
416           }
417      }
418    iconv_close(ic);
419    return new_txt;
420 }
421 #else
422 EAPI char *
423 eina_str_convert(const char *enc_from __UNUSED__, const char *enc_to __UNUSED__, const char *text __UNUSED__)
424 {
425    return NULL;
426 }
427 #endif
428
429 /**
430  * @brief Put a \ before and Space( ), \ or ' in a string.
431  *
432  * @param str the string to escape
433  *
434  * A newly allocated string is returned.
435  */
436 EAPI char *
437 eina_str_escape(const char *str)
438 {
439    char *s2, *d;
440    const char *s;
441
442    s2 = malloc((strlen(str) * 2) + 1);
443    if (!s2) return NULL;
444    for (s = str, d = s2; *s != 0; s++, d++)
445      {
446         if ((*s == ' ') || (*s == '\\') || (*s == '\''))
447           {
448              *d = '\\';
449              d++;
450           }
451         *d = *s;
452      }
453    *d = 0;
454    return s2;
455 }