EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_strbuf_common.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #ifdef _WIN32
10 # include <Evil.h>
11 #endif
12
13 #include "eina_private.h"
14 #include "eina_str.h"
15 #include "eina_magic.h"
16 #include "eina_error.h"
17 #include "eina_safety_checks.h"
18 #include "eina_strbuf.h"
19 #include "eina_strbuf_common.h"
20
21 /*============================================================================*
22 *                                  Local                                     *
23 *============================================================================*/
24
25 /**
26  * @cond LOCAL
27  */
28
29 #define EINA_STRBUF_INIT_SIZE 32
30 #define EINA_STRBUF_INIT_STEP 32
31 #define EINA_STRBUF_MAX_STEP 4096
32
33 /**
34  * @endcond
35  */
36
37 /*============================================================================*
38 *                                 Global                                     *
39 *============================================================================*/
40
41 /**
42  * @internal
43  * @brief Initialize the strbuf module.
44  *
45  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
46  *
47  * This function sets up the strbuf module of Eina. It is called by
48  * eina_init().
49  *
50  * @see eina_init()
51  */
52 Eina_Bool
53 eina_strbuf_common_init(void)
54 {
55    return EINA_TRUE;
56 }
57
58 /**
59  * @internal
60  * @brief Shut down the strbuf module.
61  *
62  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
63  *
64  * This function shuts down the strbuf module set up by
65  * eina_strbuf_common_init(). It is called by eina_shutdown().
66  *
67  * @see eina_shutdown()
68  */
69 Eina_Bool
70 eina_strbuf_common_shutdown(void)
71 {
72    return EINA_TRUE;
73 }
74
75 /**
76  * @internal
77  *
78  * init the buffer
79  * @param csize the character size
80  * @param buf the buffer to init
81  *
82  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
83  */
84 static Eina_Bool
85 _eina_strbuf_common_init(size_t csize, Eina_Strbuf *buf)
86 {
87    buf->len = 0;
88    buf->size = EINA_STRBUF_INIT_SIZE;
89    buf->step = EINA_STRBUF_INIT_STEP;
90    
91    eina_error_set(0);
92    buf->buf = calloc(csize, buf->size);
93    if (EINA_UNLIKELY(!buf->buf))
94      {
95         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
96         return EINA_FALSE;
97      }
98
99    return EINA_TRUE;
100 }
101
102 /**
103  * @internal
104  *
105  * init the buffer without allocating the actual string (for managed)
106  * @param csize the character size
107  * @param buf the buffer to init
108  *
109  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
110  */
111 static Eina_Bool
112 _eina_strbuf_common_manage_init(size_t csize __UNUSED__,
113                                  Eina_Strbuf *buf,
114                                  void *str,
115                                  size_t len)
116 {
117    buf->len = len;
118    buf->size = len + 1;
119    buf->step = EINA_STRBUF_INIT_STEP;
120    buf->buf = str;
121
122    return EINA_TRUE;
123 }
124
125
126 /**
127  * @internal
128  *
129  * resize the buffer
130  * @param csize the character size
131  * @param buf the buffer to resize
132  * @param size the minimum size of the buffer
133  *
134  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
135  */
136 static inline Eina_Bool
137 _eina_strbuf_common_resize(size_t csize, Eina_Strbuf *buf, size_t size)
138 {
139    size_t new_size, new_step, delta;
140    void *buffer;
141
142    size += 1; // Add extra space for '\0'
143
144    /* nothing to do */
145    if (size == buf->size) return EINA_TRUE;
146    else if (size > buf->size) delta = size - buf->size;
147    else delta = buf->size - size;
148
149    /* check if should keep the same step (just used while growing) */
150    if ((delta <= buf->step) && (size > buf->size)) new_step = buf->step;
151    else
152      {
153         new_step = (((delta / EINA_STRBUF_INIT_STEP) + 1)
154                     * EINA_STRBUF_INIT_STEP);
155         if (new_step > EINA_STRBUF_MAX_STEP) new_step = EINA_STRBUF_MAX_STEP;
156      }
157
158    new_size = (((size / new_step) + 1) * new_step);
159
160    /* reallocate the buffer to the new size */
161    buffer = realloc(buf->buf, new_size * csize);
162    if (EINA_UNLIKELY(!buffer))
163      {
164         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
165         return EINA_FALSE;
166      }
167
168    buf->buf = buffer;
169    buf->size = new_size;
170    buf->step = new_step;
171    eina_error_set(0);
172    return EINA_TRUE;
173 }
174
175 /**
176  * @internal
177  *
178  * If required, enlarge the buffer to fit the new size.
179  *
180  * @param csize the character size
181  * @param buf the buffer to resize
182  * @param size the minimum size of the buffer
183  *
184  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
185  */
186 Eina_Bool
187 _eina_strbuf_common_grow(size_t csize, Eina_Strbuf *buf, size_t size)
188 {
189    if ((size + 1) < buf->size) return EINA_TRUE;
190    return _eina_strbuf_common_resize(csize, buf, size);
191 }
192
193 /**
194  * @internal
195  *
196  * insert string of known length at random within existing strbuf limits.
197  *
198  * @param csize the character size
199  * @param buf the buffer to resize, must be valid.
200  * @param str the string to copy, must be valid (!NULL and smaller than @a len)
201  * @param len the amount of bytes in @a str to copy, must be valid.
202  * @param pos the position inside buffer to insert, must be valid (smaller
203  *        than eina_strbuf_common_length_get())
204  *
205  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
206  */
207 static inline Eina_Bool
208 _eina_strbuf_common_insert_length(size_t csize,
209                                   Eina_Strbuf *buf,
210                                   const void *str,
211                                   size_t len,
212                                   size_t pos)
213 {
214    if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
215       return EINA_FALSE;
216
217    /* move the existing text */
218    memmove(((unsigned char *)(buf->buf)) + ((len + pos) * csize), 
219            ((unsigned char *)(buf->buf)) + (pos * csize),
220            (buf->len - pos) * csize);
221
222    /* and now insert the given string */
223    memcpy((unsigned char *)buf->buf + (pos * csize), str, len * csize);
224
225    buf->len += len;
226    memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize);
227    return EINA_TRUE;
228 }
229
230 /*============================================================================*
231 *                                   API                                      *
232 *============================================================================*/
233
234 /**
235  * @internal
236  * @brief Create a new string buffer.
237  *
238  * @param csize the character size
239  * @return Newly allocated string buffer instance.
240  *
241  * This function creates a new string buffer. On error, @c NULL is
242  * returned and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To
243  * free the resources, use eina_strbuf_common_free().
244  *
245  * @see eina_strbuf_common_free()
246  * @see eina_strbuf_common_append()
247  * @see eina_strbuf_common_string_get()
248  */
249 Eina_Strbuf *
250 eina_strbuf_common_new(size_t csize)
251 {
252    Eina_Strbuf *buf;
253
254    eina_error_set(0);
255    buf = malloc(sizeof(Eina_Strbuf));
256    if (EINA_UNLIKELY(!buf))
257      {
258         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
259         return NULL;
260      }
261    if (EINA_UNLIKELY(!_eina_strbuf_common_init(csize, buf)))
262      {
263         eina_strbuf_common_free(buf);
264         return NULL;
265      }
266    return buf;
267 }
268
269 /**
270  * @internal
271  * @brief Create a new string buffer managing str.
272  *
273  * @param csize the character size
274  * @param str the string to manage
275  * @param len the length of the string to manage
276  * @return Newly allocated string buffer instance.
277  *
278  * This function creates a new string buffer. On error, @c NULL is
279  * returned and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To
280  * free the resources, use eina_strbuf_common_free().
281  *
282  * @see eina_strbuf_common_free()
283  * @see eina_strbuf_common_append()
284  * @see eina_strbuf_common_string_get()
285  * @since 1.1.0
286  */
287 Eina_Strbuf *
288 eina_strbuf_common_manage_new(size_t csize,
289                                void *str,
290                                size_t len)
291 {
292    Eina_Strbuf *buf;
293
294    eina_error_set(0);
295    buf = malloc(sizeof(Eina_Strbuf));
296    if (EINA_UNLIKELY(!buf))
297      {
298         eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
299         return NULL;
300      }
301   if (EINA_UNLIKELY(!_eina_strbuf_common_manage_init(csize, buf, str, len)))
302     {
303         eina_strbuf_common_free(buf);
304         return NULL;
305      }
306    return buf;
307 }
308
309 /**
310  * @internal
311  * @brief Free a string buffer.
312  *
313  * @param buf The string buffer to free.
314  *
315  * This function frees the memory of @p buf. @p buf must have been
316  * created by eina_strbuf_common_new().
317  */
318 void
319 eina_strbuf_common_free(Eina_Strbuf *buf)
320 {
321    free(buf->buf);
322    free(buf);
323 }
324
325 /**
326  * @internal
327  * @brief Reset a string buffer.
328  *
329  * @param csize the character size
330  * @param buf The string buffer to reset.
331  *
332  * This function reset @p buf: the buffer len is set to 0, and the
333  * string is set to '\\0'. No memory is free'd.
334  */
335 void
336 eina_strbuf_common_reset(size_t csize, Eina_Strbuf *buf)
337 {
338    buf->len = 0;
339    buf->step = EINA_STRBUF_INIT_STEP;
340    memset(buf->buf, 0, csize);
341 }
342
343 /**
344  * @internal
345  * @brief Append a string to a buffer, reallocating as necessary.
346  *
347  * @param csize the character size
348  * @param buf The string buffer to append to.
349  * @param str The string to append.
350  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
351  *
352  * This function appends @p str to @p buf. It computes the length of
353  * @p str, so is slightly slower than eina_strbuf_common_append_length(). If
354  * the length is known beforehand, consider using that variant. If
355  * @p buf can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
356  * returned.
357  *
358  * @see eina_strbuf_common_append()
359  * @see eina_strbuf_common_append_length()
360  */
361 Eina_Bool
362 eina_strbuf_common_append(size_t csize,
363                           Eina_Strbuf *buf,
364                           const void *str,
365                           size_t len)
366 {
367    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
368
369    if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
370       return EINA_FALSE;
371    memcpy(((unsigned char *)(buf->buf)) + (buf->len * csize), str, 
372           (len + 1) * csize);
373    buf->len += len;
374    return EINA_TRUE;
375 }
376
377 /**
378  * @internal
379  * @brief Append a string to a buffer, reallocating as necessary,
380  * limited by the given length.
381  *
382  * @param csize the character size
383  * @param buf The string buffer to append to.
384  * @param str The string to append.
385  * @param maxlen The maximum number of characters to append.
386  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
387  *
388  * This function appends at most @p maxlen characters of @p str to
389  * @p buf. It can't appends more than the length of @p str. It
390  * computes the length of @p str, so is slightly slower than
391  * eina_strbuf_common_append_length(). If the length is known beforehand,
392  * consider using that variant (@p maxlen should then be checked so
393  * that it is greater than the size of @p str). If @p str can not be
394  * appended, #EINA_FALSE is returned, otherwise, #EINA_TRUE is
395  * returned.
396  *
397  * @see eina_strbuf_common_append()
398  * @see eina_strbuf_common_append_length()
399  */
400 Eina_Bool
401 eina_strbuf_common_append_n(size_t csize,
402                             Eina_Strbuf *buf,
403                             const void *str,
404                             size_t len,
405                             size_t maxlen)
406 {
407    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
408
409    if (len > maxlen) len = maxlen;
410    if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
411       return EINA_FALSE;
412    memcpy(((unsigned char *)(buf->buf)) + (buf->len * csize), str, 
413           len * csize);
414    buf->len += len;
415    memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize);
416    return EINA_TRUE;
417 }
418
419 /**
420  * @internal
421  * @brief Append a string of exact length to a buffer, reallocating as necessary.
422  *
423  * @param csize the character size
424  * @param buf The string buffer to append to.
425  * @param str The string to append.
426  * @param length The exact length to use.
427  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
428  *
429  * This function appends @p str to @p buf. @p str must be of size at
430  * most @p length. It is slightly faster than eina_strbuf_common_append() as
431  * it does not compute the size of @p str. It is useful when dealing
432  * with strings of known size, such as eina_strngshare. If @p buf
433  * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
434  * returned.
435  *
436  * @see eina_stringshare_length()
437  * @see eina_strbuf_common_append()
438  * @see eina_strbuf_common_append_n()
439  */
440 Eina_Bool
441 eina_strbuf_common_append_length(size_t csize,
442                                  Eina_Strbuf *buf,
443                                  const void *str,
444                                  size_t length)
445 {
446    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
447
448    if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + length)))
449       return EINA_FALSE;
450    memcpy(((unsigned char *)(buf->buf)) + (buf->len * csize), str,
451           length * csize);
452    buf->len += length;
453    memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize);
454    return EINA_TRUE;
455 }
456
457 /**
458  * @internal
459  * @brief Insert a string to a buffer, reallocating as necessary.
460  *
461  * @param csize the character size
462  * @param buf The string buffer to insert.
463  * @param str The string to insert.
464  * @param pos The position to insert the string.
465  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
466  *
467  * This function inserts @p str to @p buf at position @p pos. It
468  * computes the length of @p str, so is slightly slower than
469  * eina_strbuf_common_insert_length(). If  the length is known beforehand,
470  * consider using that variant. If @p buf can't insert it, #EINA_FALSE
471  * is returned, otherwise #EINA_TRUE is returned.
472  */
473 Eina_Bool
474 eina_strbuf_common_insert(size_t csize,
475                           Eina_Strbuf *buf,
476                           const void *str,
477                           size_t len,
478                           size_t pos)
479 {
480    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
481
482    if (pos >= buf->len) return eina_strbuf_common_append(csize, buf, str, len);
483    return _eina_strbuf_common_insert_length(csize, buf, str, len, pos);
484 }
485
486 /**
487  * @internal
488  * @brief Insert a string to a buffer, reallocating as necessary. Limited by maxlen.
489  *
490  * @param csize the character size
491  * @param buf The string buffer to insert to.
492  * @param str The string to insert.
493  * @param maxlen The maximum number of chars to insert.
494  * @param pos The position to insert the string.
495  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
496  *
497  * This function inserts @p str ot @p buf at position @p pos, with at
498  * most @p maxlen bytes. The number of inserted characters can not be
499  * greater than the length of @p str. It computes the length of
500  * @p str, so is slightly slower than eina_strbuf_common_insert_length(). If the
501  * length is known beforehand, consider using that variant (@p maxlen
502  * should then be checked so that it is greater than the size of
503  * @p str). If @p str can not be inserted, #EINA_FALSE is returned,
504  * otherwise, #EINA_TRUE is returned.
505  */
506 Eina_Bool
507 eina_strbuf_common_insert_n(size_t csize,
508                             Eina_Strbuf *buf,
509                             const void *str,
510                             size_t len,
511                             size_t maxlen,
512                             size_t pos)
513 {
514    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
515
516    if (pos >= buf->len)
517       return eina_strbuf_common_append_n(csize, buf, str, len, maxlen);
518    if (len > maxlen) len = maxlen;
519    return _eina_strbuf_common_insert_length(csize, buf, str, len, pos);
520 }
521
522 /**
523  * @internal
524  * @brief Insert a string of exact length to a buffer, reallocating as necessary.
525  *
526  * @param csize the character size
527  * @param buf The string buffer to insert to.
528  * @param str The string to insert.
529  * @param length The exact length to use.
530  * @param pos The position to insert the string.
531  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
532  *
533  * This function inserts @p str to @p buf. @p str must be of size at
534  * most @p length. It is slightly faster than eina_strbuf_common_insert() as
535  * it does not compute the size of @p str. It is useful when dealing
536  * with strings of known size, such as eina_strngshare. If @p buf
537  * can't insert it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
538  * returned.
539  *
540  * @see eina_stringshare_length()
541  * @see eina_strbuf_common_insert()
542  * @see eina_strbuf_common_insert_n()
543  */
544 Eina_Bool
545 eina_strbuf_common_insert_length(size_t csize,
546                                  Eina_Strbuf *buf,
547                                  const void *str,
548                                  size_t length,
549                                  size_t pos)
550 {
551    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
552
553    if (pos >= buf->len)
554       return eina_strbuf_common_append_length(csize, buf, str, length);
555    return _eina_strbuf_common_insert_length(csize, buf, str, length, pos);
556 }
557
558 /**
559  * @internal
560  * @brief Append a character to a string buffer, reallocating as
561  * necessary.
562  *
563  * @param csize the character size
564  * @param buf The string buffer to append to.
565  * @param c The char to append.
566  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
567  *
568  * This function inserts @p c to @p buf. If it can not insert it, #EINA_FALSE
569  * is returned, otherwise #EINA_TRUE is returned.
570  */
571 Eina_Bool
572 eina_strbuf_common_append_char(size_t csize, Eina_Strbuf *buf, const void *c)
573 {
574    if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + 1)))
575       return EINA_FALSE;
576
577    memcpy(((unsigned char *)(buf->buf)) + ((buf->len)++ *csize), c, csize);
578    memset(((unsigned char *)(buf->buf)) + (buf->len * csize), 0, csize);
579    return EINA_TRUE;
580 }
581
582 /**
583  * @internal
584  * @brief Insert a character to a string buffer, reallocating as
585  * necessary.
586  *
587  * @param csize the character size
588  * @param buf The string buffer to insert to.
589  * @param c The char to insert.
590  * @param pos The position to insert the char.
591  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
592  *
593  * This function inserts @p c to @p buf at position @p pos. If @p buf
594  * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
595  * returned.
596  */
597 Eina_Bool
598 eina_strbuf_common_insert_char(size_t csize,
599                                Eina_Strbuf *buf,
600                                const void *c,
601                                size_t pos)
602 {
603    if (pos >= buf->len)
604       return eina_strbuf_common_append_char(csize, buf, c);
605    return _eina_strbuf_common_insert_length(csize, buf, c, 1, pos);
606 }
607
608 /**
609  * @internal
610  * @brief Remove a slice of the given string buffer.
611  *
612  * @param csize the character size
613  * @param buf The string buffer to remove a slice.
614  * @param start The initial (inclusive) slice position to start
615  *        removing, in bytes.
616  * @param end The final (non-inclusive) slice position to finish
617  *        removing, in bytes.
618  * @return #EINA_TRUE on success, #EINA_FALSE on failure.
619  *
620  * This function removes a slice of @p buf, starting at @p start
621  * (inclusive) and ending at @p end (non-inclusive). Both values are
622  * in bytes. It returns #EINA_FALSE on failure, #EINA_TRUE otherwise.
623  */
624 Eina_Bool
625 eina_strbuf_common_remove(size_t csize,
626                           Eina_Strbuf *buf,
627                           size_t start,
628                           size_t end)
629 {
630    size_t remove_len, tail_len;
631
632    if (end >= buf->len) end = buf->len;
633    if (end <= start) return EINA_TRUE;
634
635    remove_len = end - start;
636    if (remove_len == buf->len)
637      {
638         free(buf->buf);
639         return _eina_strbuf_common_init(csize, buf);
640      }
641
642    tail_len = buf->len - end + 1; /* includes '\0' */
643    memmove(((unsigned char *)(buf->buf)) + (start * csize),
644            ((unsigned char *)(buf->buf)) + (end * csize),
645            tail_len * csize);
646    buf->len -= remove_len;
647    return _eina_strbuf_common_resize(csize, buf, buf->len);
648 }
649
650 /**
651  * @internal
652  * @brief Retrieve a pointer to the contents of a string buffer
653  *
654  * @param buf The string buffer.
655  * @return The current string in the string buffer.
656  *
657  * This function returns the string contained in @p buf. The returned
658  * value must not be modified and will no longer be valid if @p buf is
659  * modified. In other words, any eina_strbuf_common_append() or similar will
660  * make that pointer invalid.
661  *
662  * @see eina_strbuf_common_string_steal()
663  */
664 const void *
665 eina_strbuf_common_string_get(const Eina_Strbuf *buf)
666 {
667    return buf->buf;
668 }
669
670 /**
671  * @internal
672  * @brief Steal the contents of a string buffer.
673  *
674  * @param csize the character size
675  * @param buf The string buffer to steal.
676  * @return The current string in the string buffer.
677  *
678  * This function returns the string contained in @p buf. @p buf is
679  * then initialized and does not own the returned string anymore. The
680  * caller must release the memory of the returned string by calling
681  * free().
682  *
683  * @see eina_strbuf_common_string_get()
684  */
685 void *
686 eina_strbuf_common_string_steal(size_t csize, Eina_Strbuf *buf)
687 {
688    void *ret;
689
690    ret = buf->buf;
691    // TODO: Check return value and do something clever
692    _eina_strbuf_common_init(csize, buf);
693    return ret;
694 }
695
696 /**
697  * @internal
698  * @brief Free the contents of a string buffer but not the buffer.
699  *
700  * @param csize the character size
701  * @param buf The string buffer to free the string of.
702  *
703  * This function frees the string contained in @p buf without freeing
704  * @p buf.
705  */
706 void
707 eina_strbuf_common_string_free(size_t csize, Eina_Strbuf *buf)
708 {
709    free(buf->buf);
710    _eina_strbuf_common_init(csize, buf);
711 }
712
713 /**
714  * @internal
715  * @brief Retrieve the length of the string buffer content.
716  *
717  * @param buf The string buffer.
718  * @return The current length of the string, in bytes.
719  *
720  * This function returns the length of @p buf.
721  */
722 size_t
723 eina_strbuf_common_length_get(const Eina_Strbuf *buf)
724 {
725    return buf->len;
726 }
727
728 /**
729  * @cond LOCAL
730  */
731
732 /*FIXME: Implementing them here is a hack! */
733
734 #ifdef _STRBUF_CSIZE
735 # undef _STRBUF_CSIZE
736 #endif
737
738 #ifdef _STRBUF_MAGIC
739 # undef _STRBUF_MAGIC
740 #endif
741
742 #ifdef _STRBUF_MAGIC_STR
743 # undef _STRBUF_MAGIC_STR
744 #endif
745
746 #define _STRBUF_CSIZE 1
747 #define _STRBUF_MAGIC             EINA_MAGIC_STRBUF
748 #define _STRBUF_MAGIC_STR         __STRBUF_STR_MAGIC_STR
749 static const char __STRBUF_STR_MAGIC_STR[] = "Eina Strbuf";
750
751
752 /**
753  * @endcond
754  */
755
756
757 EAPI Eina_Bool
758 eina_strbuf_replace(Eina_Strbuf *buf,
759                     const char *str,
760                     const char *with,
761                     unsigned int n)
762 {
763    size_t len1, len2;
764    char *spos;
765    size_t pos;
766
767    EINA_SAFETY_ON_NULL_RETURN_VAL( str, EINA_FALSE);
768    EINA_SAFETY_ON_NULL_RETURN_VAL(with, EINA_FALSE);
769    EINA_MAGIC_CHECK_STRBUF(buf, 0);
770    if (n == 0) return EINA_FALSE;
771
772    spos = buf->buf;
773    while (n--)
774      {
775         spos = strstr(spos, str);
776         if (!spos || *spos == '\0') return EINA_FALSE;
777         if (n) spos++;
778      }
779
780    pos = spos - (const char *)buf->buf;
781    len1 = strlen(str);
782    len2 = strlen(with);
783    if (len1 != len2)
784      {
785         /* resize the buffer if necessary */
786         if (EINA_UNLIKELY(!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf,
787                                                     buf->len - len1 + len2)))
788            return EINA_FALSE; /* move the existing text */
789         memmove(((unsigned char *)(buf->buf)) + pos + len2, 
790                 ((unsigned char *)(buf->buf)) + pos + len1,
791                 buf->len - pos - len1);
792      }
793    /* and now insert the given string */
794    memcpy(((unsigned char *)(buf->buf)) + pos, with, len2);
795    buf->len += len2 - len1;
796    memset(((unsigned char *)(buf->buf)) + buf->len, 0, 1);
797    return EINA_TRUE;
798 }
799
800 EAPI int
801 eina_strbuf_replace_all(Eina_Strbuf *buf, const char *str, const char *with)
802 {
803    size_t len1, len2, len;
804    char *tmp_buf = NULL;
805    char *spos;
806    size_t pos, start;
807    size_t pos_tmp, start_tmp;
808    int n = 0;
809
810    EINA_SAFETY_ON_NULL_RETURN_VAL( str, 0);
811    EINA_SAFETY_ON_NULL_RETURN_VAL(with, 0);
812    EINA_MAGIC_CHECK_STRBUF(buf, 0);
813
814    spos = strstr(buf->buf, str);
815    if (!spos || *spos == '\0') return 0;
816    len1 = strlen(str);
817    len2 = strlen(with);
818    /* if the size of the two string is equal, it is fairly easy to replace them
819     * we don't need to resize the buffer or doing other calculations */
820    if (len1 == len2)
821      {
822         while (spos)
823           {
824              memcpy(spos, with, len2);
825              spos = strstr(spos + len2, str);
826              n++;
827           }
828         return n;
829      }
830    pos = pos_tmp = spos - (const char *)buf->buf;
831    tmp_buf = buf->buf;
832    buf->buf = malloc(buf->size);
833    if (EINA_UNLIKELY(!buf->buf))
834      {
835         buf->buf = tmp_buf;
836         return 0;
837      }
838    start = start_tmp = 0;
839    len = buf->len;
840    while (spos)
841      {
842         n++;
843         len = (len + len2) - len1;
844         /* resize the buffer if necessary */
845         if (EINA_UNLIKELY(!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf, len)))
846           {
847              /* we have to stop replacing here, because we haven't enough
848               * memory to go on */
849              len = (len + len1) - len2;
850              break;
851           }
852         /* copy the untouched text */
853         memcpy(((unsigned char *)(buf->buf)) + start,  tmp_buf + start_tmp,
854                pos - start);
855         /* copy the new string */
856         memcpy(((unsigned char *)(buf->buf)) + pos, with, len2);
857         /* calculate the next positions */
858         start_tmp = pos_tmp + len1;
859         start = pos + len2;
860         spos = strstr(tmp_buf + start_tmp, str);
861         /* this calculations don't make sense if spos == NULL, but the
862          * calculated values won't be used, because the loop will stop
863          * then */
864         pos_tmp = spos - tmp_buf;
865         pos = start + pos_tmp - start_tmp;
866      }
867    /* and now copy the rest of the text */
868    memcpy(((unsigned char *)(buf->buf)) + start, tmp_buf + start_tmp,
869           len - start);
870    buf->len = len;
871    memset(((unsigned char *)(buf->buf)) + buf->len, 0, 1);
872    free(tmp_buf);
873    return n;
874 }