Tizen 2.1 base
[framework/uifw/ecore.git] / src / lib / ecore / ecore_strbuf.c
1 #include "ecore_private.h"
2 #include "Ecore.h"
3 #include "Ecore_Data.h"
4 #include "Ecore_Str.h"
5
6 #define ECORE_STRBUF_INIT_SIZE 32
7 #define ECORE_STRBUF_INIT_STEP 32
8 #define ECORE_STRBUF_MAX_STEP 4096
9
10 struct _ecore_strbuf
11 {
12   char *buf;
13   size_t len;
14   size_t size;
15   size_t step;
16 };
17
18 static int _ecore_strbuf_resize(Ecore_Strbuf *buf, size_t size);
19
20 /**
21  * Create a new string buffer
22  */
23 EAPI Ecore_Strbuf *
24 ecore_strbuf_new(void)
25 {
26   Ecore_Strbuf *buf;
27
28   buf = malloc(sizeof(Ecore_Strbuf));
29   if (!buf) return NULL;
30
31   buf->len = 0;
32   buf->size = ECORE_STRBUF_INIT_SIZE;
33   buf->step = ECORE_STRBUF_INIT_STEP;
34
35   buf->buf = malloc(buf->size);
36   buf->buf[0] = '\0';
37
38   return buf;
39 }
40
41 /**
42  * Free a string buffer
43  * @param buf the buffer to free
44  */
45 EAPI void
46 ecore_strbuf_free(Ecore_Strbuf *buf)
47 {
48   CHECK_PARAM_POINTER("buf", buf); 
49   free(buf->buf);
50   free(buf);
51 }
52
53 /**
54  * Append a string to a buffer, reallocating as necessary.
55  * @param buf the Ecore_Strbuf to append to
56  * @param str the string to append
57  */
58 EAPI void
59 ecore_strbuf_append(Ecore_Strbuf *buf, const char *str)
60 {
61   size_t l;
62   size_t off = 0;
63
64   CHECK_PARAM_POINTER("buf", buf); 
65   CHECK_PARAM_POINTER("str", str); 
66
67   l = ecore_strlcpy(buf->buf + buf->len, str, buf->size - buf->len);
68
69   while (l > buf->size - buf->len) 
70     {
71         /* we successfully appended this much */
72         off += buf->size - buf->len - 1;
73         buf->len = buf->size - 1;
74         buf->size += buf->step;
75         if (buf->step < ECORE_STRBUF_MAX_STEP)
76           buf->step *= 2;
77         buf->buf = realloc(buf->buf, buf->size);
78         *(buf->buf + buf->len) = '\0';
79
80         l = ecore_strlcpy(buf->buf + buf->len, str + off, buf->size - buf->len);
81     }
82   buf->len += l;
83 }
84
85 /**
86  * Insert a string to a buffer, reallocating as necessary.
87  * @param buf the Ecore_Strbuf to insert
88  * @param str the string to insert
89  * @param pos the position to insert the string
90  */
91 EAPI void
92 ecore_strbuf_insert(Ecore_Strbuf *buf, const char *str, size_t pos)
93 {
94   size_t len;
95
96   CHECK_PARAM_POINTER("buf", buf); 
97   CHECK_PARAM_POINTER("str", str);
98
99   if (pos >= buf->len)
100     {
101         ecore_strbuf_append(buf, str);
102         return;
103     }
104
105   /*
106    * resize the buffer if necessary
107    */
108   len = strlen(str);
109   if (!_ecore_strbuf_resize(buf, buf->len + len))
110     return;
111   /* move the existing text */
112   memmove(buf->buf + len + pos, buf->buf + pos, buf->len - pos);
113   /* and now insert the given string */
114   memcpy(buf->buf + pos, str, len);
115   buf->len += len;
116   buf->buf[buf->len] = 0;
117 }
118
119 /**
120  * Append a character to a string buffer, reallocating as necessary.
121  * @param buf the Ecore_Strbuf to append to
122  * @param c the char to append
123  */
124 EAPI void
125 ecore_strbuf_append_char(Ecore_Strbuf *buf, char c)
126 {
127   CHECK_PARAM_POINTER("buf", buf); 
128   if (buf->len >= buf->size - 1)
129   {
130       buf->size += buf->step;
131       if (buf->step < ECORE_STRBUF_MAX_STEP)
132         buf->step *= 2;
133       buf->buf = realloc(buf->buf, buf->size);
134   }
135
136   buf->buf[(buf->len)++] = c;
137   buf->buf[buf->len] = '\0';
138 }
139
140 /**
141  * Retrieve a pointer to the contents of a string buffer
142  * @param buf the buffer
143  *
144  * This pointer must not be modified, and will no longer be valid if
145  * the Ecore_Strbuf is modified.
146  */
147 EAPI const char *
148 ecore_strbuf_string_get(Ecore_Strbuf *buf)
149 {
150   CHECK_PARAM_POINTER_RETURN("buf", buf, NULL); 
151   return buf->buf;
152 }
153
154 /**
155  * Retrieve the length of the string buffer content
156  * @param buf the buffer
157  */
158 EAPI size_t
159 ecore_strbuf_length_get(Ecore_Strbuf *buf)
160 {
161   CHECK_PARAM_POINTER_RETURN("buf", buf, 0); 
162   return buf->len;
163 }
164
165 /**
166  * Replace the n-th string with an other string.
167  * @param buf the Ecore_Strbuf to work with
168  * @param str the string to replace
169  * @param with the replaceing string
170  * @param n the number of the fitting string 
171  *
172  * @return true on success
173  */
174 EAPI int
175 ecore_strbuf_replace(Ecore_Strbuf *buf, const char *str, const char *with,
176                      unsigned int n)
177 {
178   size_t len1, len2;
179   char *spos;
180   size_t pos;
181
182   CHECK_PARAM_POINTER_RETURN("buf", buf, 0); 
183   CHECK_PARAM_POINTER_RETURN("str", str, 0);
184   CHECK_PARAM_POINTER_RETURN("with", with, 0);
185
186   if (n == 0)
187      return 0;
188
189   spos = buf->buf;
190   while (n--)
191     {
192         spos = strstr(spos, str);
193         if (!spos || *spos == '\0')
194            return 0;
195         if (n) spos++;
196     }
197
198   pos = spos - buf->buf;
199   len1 = strlen(str); 
200   len2 = strlen(with);
201   if (len1 != len2)
202     {
203         /* resize the buffer if necessary */
204         if (!_ecore_strbuf_resize(buf, buf->len - len1 + len2))
205            return 0;
206         /* move the existing text */
207         memmove(buf->buf + pos + len2, buf->buf + pos + len1, 
208                         buf->len - pos - len1);
209     }
210   /* and now insert the given string */
211   memcpy(buf->buf + pos, with, len2);
212   buf->len += len2 - len1;
213   buf->buf[buf->len] = 0;
214
215   return 1;
216 }
217
218 /**
219  * Replace all strings with an other string.
220  * @param buf the Ecore_Strbuf to work with
221  * @param str the string to replace
222  * @param with the replaceing string
223  *
224  * @return how often the string was replaced
225  */
226 EAPI int
227 ecore_strbuf_replace_all(Ecore_Strbuf *buf, const char *str, const char *with)
228 {
229   size_t len1, len2, len;
230   char *tmp_buf = NULL;
231   char *spos;
232   size_t pos, start;
233   size_t pos_tmp, start_tmp;
234   int n = 0;
235
236   CHECK_PARAM_POINTER_RETURN("buf", buf, 0); 
237   CHECK_PARAM_POINTER_RETURN("str", str, 0);
238   CHECK_PARAM_POINTER_RETURN("with", with, 0);
239
240   spos = strstr(buf->buf, str);
241   if (!spos || *spos == '\0')
242      return 0;
243
244   len1 = strlen(str); 
245   len2 = strlen(with);
246
247   /* if the size of the two string is equal, it is fairly easy to replace them
248    * we don't need to resize the buffer or doing other calculations */
249   if (len1 == len2)
250     {
251         while (spos)
252            {
253                memcpy(spos, with, len2);
254                spos = strstr(spos + len2, str);
255                n++;
256            }
257         return n;
258     }
259   
260   pos = pos_tmp = spos - buf->buf;
261   tmp_buf = buf->buf;
262   buf->buf = malloc(buf->size);
263   if (!buf->buf)
264      {
265          buf->buf = tmp_buf;
266          return 0;
267      }
268   start = start_tmp = 0;
269   len = buf->len;
270
271   while (spos)
272      {
273         n++;
274         len = (len + len2) - len1;
275         /* resize the buffer if necessary */
276         if (!_ecore_strbuf_resize(buf, len))
277            {
278                /* we have to stop replacing here, because we haven't enough
279                 * memory to go on */
280                len = (len + len1) - len2;
281                break;
282            }
283         
284         /* copy the untouched text */
285         memcpy(buf->buf + start, tmp_buf + start_tmp, pos - start);
286         /* copy the new string */
287         memcpy(buf->buf + pos, with, len2);
288
289         /* calculate the next positions */
290         start_tmp = pos_tmp + len1;
291         start = pos + len2;
292         spos = strstr(tmp_buf + start_tmp, str);
293         /* this calculations don't make sense if spos == NULL, but the
294          * calculated values won't be used, because the loop will stop
295          * then */
296         pos_tmp = spos - tmp_buf;
297         pos = start + pos_tmp - start_tmp;
298     }
299   /* and now copy the rest of the text */
300   memcpy(buf->buf + start, tmp_buf + start_tmp, len - start);
301   buf->len = len;
302   buf->buf[buf->len] = 0;
303
304   free(tmp_buf);
305
306   return n;
307 }
308
309
310 /**
311  * resize the buffer
312  * @param buf the buffer to resize
313  * @param size the minimum size of the buffer
314  */
315 static int 
316 _ecore_strbuf_resize(Ecore_Strbuf *buf, size_t size)
317 {
318   char *buffer;
319   size_t new_size;
320   size_t new_step;
321
322   new_size = buf->size;
323   new_step = buf->step;
324
325   /*
326    * first we have to determine the new buffer size
327    */
328   if (size == buf->size)
329     /* nothing to do */
330     return 1;
331   else if (size > buf->size)
332     {
333         /* enlarge the buffer */
334         while (size > new_size)
335            {
336                new_size += new_step;
337                if (new_step < ECORE_STRBUF_MAX_STEP)
338                   new_step *= 2;
339            }
340     }
341   else 
342     {
343         /* shrink the buffer */
344         /*
345          * to be done
346          */
347         return 1;
348     }
349
350   /* reallocate the buffer to the new size */
351   buffer = realloc(buf->buf, new_size);
352   if (!buffer)
353     return 0;
354   
355   buf->buf = buffer;
356   buf->size = new_size;
357   buf->step = new_step;
358   return 1;
359 }
360