aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_strbuf_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_strbuf_common.c')
-rw-r--r--libraries/eina/src/lib/eina_strbuf_common.c874
1 files changed, 874 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_strbuf_common.c b/libraries/eina/src/lib/eina_strbuf_common.c
new file mode 100644
index 0000000..46067cd
--- /dev/null
+++ b/libraries/eina/src/lib/eina_strbuf_common.c
@@ -0,0 +1,874 @@
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 */
52Eina_Bool
53eina_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 */
69Eina_Bool
70eina_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 */
84static 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 */
111static 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 */
136static 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 */
186Eina_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 */
207static 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 */
249Eina_Strbuf *
250eina_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 */
287Eina_Strbuf *
288eina_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 */
318void
319eina_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 */
335void
336eina_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
356 * #EINA_TRUE is returned.
357 *
358 * @see eina_strbuf_common_append()
359 * @see eina_strbuf_common_append_length()
360 */
361Eina_Bool
362eina_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 */
400Eina_Bool
401eina_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 */
440Eina_Bool
441eina_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 */
473Eina_Bool
474eina_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 */
506Eina_Bool
507eina_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 */
544Eina_Bool
545eina_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,
569 * #EINA_FALSE is returned, otherwise #EINA_TRUE is returned.
570 */
571Eina_Bool
572eina_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 */
597Eina_Bool
598eina_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 */
624Eina_Bool
625eina_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 */
664const void *
665eina_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 */
685void *
686eina_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 */
706void
707eina_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 */
722size_t
723eina_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
749static const char __STRBUF_STR_MAGIC_STR[] = "Eina Strbuf";
750
751
752/**
753 * @endcond
754 */
755
756
757EAPI Eina_Bool
758eina_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
800EAPI int
801eina_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}