1 /*
2   Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy
5   of this software and associated documentation files (the "Software"), to deal
6   in the Software without restriction, including without limitation the rights
7   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8   copies of the Software, and to permit persons to whom the Software is
9   furnished to do so, subject to the following conditions:
10 
11   The above copyright notice and this permission notice shall be included in
12   all copies or substantial portions of the Software.
13 
14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20   IN THE SOFTWARE.
21 */
22 
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <math.h>
30 #include <float.h>
31 #include <regex.h>
32 
33 #include "../ows/ows.h"
34 
35 
36 #ifndef SIZE_MAX
37 #define SIZE_MAX (~(size_t)0)
38 #endif
39 
40 /*
41  * Realloc buffer memory space
42  * use an exponential grow size to realloc (less realloc call)
43  */
buffer_realloc(buffer * buf)44 static void buffer_realloc(buffer * buf)
45 {
46   assert(buf);
47 
48   buf->buf = realloc(buf->buf, buf->realloc * sizeof(char));
49   assert(buf->buf);
50 
51   buf->size = buf->realloc;
52   buf->realloc *= 4;
53 
54   if (buf->realloc >= SIZE_MAX) assert(false);
55 }
56 
57 
58 /*
59  * Initialize buffer structure
60  */
buffer_init()61 buffer *buffer_init()
62 {
63   buffer *buf;
64 
65   buf = malloc(sizeof(buffer));
66   assert(buf);
67 
68   buf->buf = malloc(BUFFER_SIZE_INIT * sizeof(char));
69   assert(buf->buf);
70 
71   buf->size = BUFFER_SIZE_INIT;
72   buf->realloc = BUFFER_SIZE_INIT * 2;
73   buf->use = 0;
74   buf->buf[0] = '\0';
75 
76   return buf;
77 }
78 
79 
80 /*
81  * Free a buffer structure and all data in it
82  */
buffer_free(buffer * buf)83 void buffer_free(buffer * buf)
84 {
85   assert(buf);
86   assert(buf->buf);
87 
88   free(buf->buf);
89   buf->buf = NULL;
90 
91   free(buf);
92   buf = NULL;
93 }
94 
95 
96 /*
97  * Empty data from a given buffer
98  * (don't release memory, use buffer_free instead)
99  */
buffer_empty(buffer * buf)100 void buffer_empty(buffer * buf)
101 {
102   assert(buf);
103   if (buf->use > 0) buf->buf[0] = '\0';
104   buf->use = 0;
105 }
106 
107 
108 /*
109  * Flush all data from a buffer to a stream
110  * Not used *only* to debug purpose ;)
111  */
buffer_flush(buffer * buf,FILE * output)112 void buffer_flush(buffer * buf, FILE * output)
113 {
114   assert(buf);
115   assert(output);
116   fprintf(output, "%s", buf->buf);
117 }
118 
119 
120 /*
121  * Add a char to the bottom of a buffer
122  */
buffer_add(buffer * buf,char c)123 void buffer_add(buffer * buf, char c)
124 {
125   assert(buf);
126 
127   if ((buf->use + 1) >= buf->size) buffer_realloc(buf);
128 
129   buf->buf[buf->use] = c;
130   buf->buf[buf->use + 1] = '\0';
131   buf->use++;
132 }
133 
134 
135 /*
136  * Return a buffer from a double
137  */
buffer_ftoa(double f)138 buffer *buffer_ftoa(double f)
139 {
140   buffer *res;
141 
142   res = buffer_init();
143   while (res->size < 100) buffer_realloc(res);
144   snprintf(res->buf, 99, "%f", f);
145   res->use = strlen(res->buf);
146 
147   return res;
148 }
149 
150 
151 /*
152  * Add a double to a given buffer
153  */
buffer_add_double(buffer * buf,double f)154 void buffer_add_double(buffer * buf, double f)
155 {
156   buffer *b;
157 
158   assert(buf);
159 
160   b = buffer_ftoa(f);
161   buffer_copy(buf, b);
162   buffer_free(b);
163 }
164 
165 
166 /*
167  * Add an int to a given buffer
168  */
buffer_add_int(buffer * buf,int i)169 void buffer_add_int(buffer * buf, int i)
170 {
171   buffer *b;
172 
173   assert(buf);
174 
175   b = buffer_itoa(i);
176   buffer_copy(buf, b);
177   buffer_free(b);
178 }
179 
180 
181 /*
182  * Convert an integer to a buffer (base 10 only)
183  */
buffer_itoa(int i)184 buffer *buffer_itoa(int i)
185 {
186   buffer *res;
187 
188   res = buffer_init();
189   /* FIXME use snprintf instead ! */
190   while (res->size < 100) buffer_realloc(res);
191   sprintf(res->buf, "%i", i);
192   res->use = strlen(res->buf);
193 
194   return res;
195 }
196 
197 
buffer_from_str(const char * str)198 buffer *buffer_from_str(const char *str)
199 {
200   buffer *b;
201 
202   assert(str);
203   b = buffer_init();
204 
205   buffer_add_str(b, str);
206   return b;
207 }
208 
209 
210 /*
211  * Add a char to the top of a buffer
212  */
buffer_add_head(buffer * buf,char c)213 void buffer_add_head(buffer * buf, char c)
214 {
215   size_t i;
216 
217   assert(buf);
218 
219   if ((buf->use + 2) >= buf->size)
220     buffer_realloc(buf);
221 
222   if (buf->use > 0)
223     for (i = buf->use; i > 0; i--)
224       buf->buf[i] = buf->buf[i - 1];
225 
226   buf->buf[0] = c;
227   buf->buf[buf->use + 1] = '\0';
228   buf->use++;
229 }
230 
231 
232 /*
233  * Add a string to the top of a buffer
234  */
buffer_add_head_str(buffer * buf,char * str)235 void buffer_add_head_str(buffer * buf, char *str)
236 {
237   int i;
238 
239   assert(buf);
240   assert(str);
241 
242   for (i = strlen(str); i != 0; i--)
243     buffer_add_head(buf, str[i - 1]);
244 }
245 
246 
247 /*
248  * Add a string to a buffer
249  */
buffer_add_str(buffer * buf,const char * str)250 void buffer_add_str(buffer * buf, const char *str)
251 {
252   assert(buf);
253   assert(str);
254 
255   if ((strlen(str) + buf->use) >= buf->size)
256     while ((strlen(str) + buf->use) >= buf->size)
257       buffer_realloc(buf);
258 
259   strcat(buf->buf, str);
260   buf->use = buf->use + strlen(str);
261 }
262 
263 
264 /*
265  * Add n char from string to a buffer
266  */
buffer_add_nstr(buffer * buf,const char * str,size_t n)267 void buffer_add_nstr(buffer * buf, const char *str, size_t n)
268 {
269   assert(buf);
270   assert(str);
271   assert(n > 0);
272   assert(n <= strlen(str));
273 
274   if ((n + buf->use) >= buf->size)
275     while ((n + buf->use) >= buf->size)
276       buffer_realloc(buf);
277 
278   strncat(buf->buf, str, n);
279   buf->use = buf->use + n;
280 }
281 
282 
283 /*
284  * Check if a buffer string is the same than another
285  */
buffer_cmp(const buffer * buf,const char * str)286 bool buffer_cmp(const buffer * buf, const char *str)
287 {
288   size_t i;
289 
290   assert(buf);
291   assert(str);
292 
293   if (buf->use != strlen(str)) return false;
294 
295   for (i = 0; i < buf->use; i++)
296     if (buf->buf[i] != str[i])
297       return false;
298 
299   return true;
300 }
301 
302 
303 /*
304  * Check if a buffer string is the same than another, on the n first char
305  */
buffer_ncmp(const buffer * buf,const char * str,size_t n)306 bool buffer_ncmp(const buffer * buf, const char *str, size_t n)
307 {
308   size_t i;
309 
310   assert(buf);
311   assert(str);
312 
313   if (buf->use < n) return false;
314 
315   for (i = 0 ; i < n ; i++)
316     if (buf->buf[i] != str[i])
317       return false;
318 
319   return true;
320 }
321 
322 /*
323  * Check if a buffer string is the same than anoter for a specified length
324  * (insensitive case check)
325  */
buffer_case_cmp(const buffer * buf,const char * str)326 bool buffer_case_cmp(const buffer * buf, const char *str)
327 {
328   size_t i;
329 
330   assert(buf);
331   assert(str);
332 
333   if (buf->use != strlen(str)) return false;
334 
335   for (i = 0; i < buf->use; i++)
336     if (toupper(buf->buf[i]) != toupper(str[i]))
337       return false;
338 
339   return true;
340 }
341 
342 
343 /*
344  * Copy data from a buffer to an another
345  */
buffer_copy(buffer * dest,const buffer * src)346 void buffer_copy(buffer * dest, const buffer * src)
347 {
348   assert(dest);
349   assert(src);
350 
351   buffer_add_str(dest, src->buf);
352 }
353 
354 
355 /*
356  * Copy the whole buffer struct to an another struct
357  */
buffer_clone(buffer * buf)358 buffer *buffer_clone(buffer * buf)
359 {
360   buffer *b;
361 
362   assert(buf);
363   assert(buf->buf);
364 
365   b = buffer_init();
366   buffer_copy(b, buf);
367 
368   return b;
369 }
370 
371 
372 /*
373  * Delete last N chars from a buffer
374  */
buffer_pop(buffer * buf,size_t len)375 void buffer_pop(buffer * buf, size_t len)
376 {
377   assert(buf);
378   assert(len <= buf->use);
379 
380   buf->use -= len;
381   buf->buf[buf->use] = '\0';
382 }
383 
384 
385 /*
386  * Delete first N chars from a buffer
387  */
buffer_shift(buffer * buf,size_t len)388 void buffer_shift(buffer * buf, size_t len)
389 {
390   size_t i;
391 
392   assert(buf);
393   assert(len <= buf->use);
394 
395   if (len <= 0) return; /* nothing to do */
396 
397   for (i = len; i < buf->use; i++)
398     buf->buf[i - len] = buf->buf[i];
399 
400   buf->use -= len;
401   buf->buf[buf->use] = '\0';
402 }
403 
404 
405 /*
406  * Replace all occurences of string 'before' inside the buffer by string 'after'
407  */
buffer_replace(buffer * buf,char * before,char * after)408 buffer *buffer_replace(buffer * buf, char *before, char *after)
409 {
410   buffer *new_buf, *rest;
411   size_t length;
412   char *pos;
413 
414   assert(before);
415   assert(after);
416   assert(buf);
417 
418   if (!strcmp(before, after)) return buf; /* To prevent infinite loop */
419 
420   new_buf = buffer_init();
421   buffer_copy(new_buf, buf);
422 
423   pos = strstr(new_buf->buf, before); /* Look for first occurence */
424   while (pos) {
425     length = strlen(pos);
426 
427     buffer_pop(new_buf, length);    /* Copy the first part without occurence */
428     buffer_add_str(new_buf, after); /* Add the string after */
429 
430     /* Add the remaining string */
431     rest = buffer_init();
432     buffer_copy(rest, buf);
433     buffer_shift(rest, buf->use - length + strlen(before));
434     buffer_copy(new_buf, rest);
435     buffer_free(rest);
436 
437     pos = strstr(new_buf->buf, before); /* Search the next occurence */
438   }
439 
440   buffer_empty(buf);
441   buffer_copy(buf, new_buf);
442   buffer_free(new_buf);
443 
444   return buf;
445 }
446 
447 
448 /*
449  * Retrieve first position inside a buffer of a specific char
450  * or -1 if not found.
451  */
buffer_chr(const buffer * buf,char c)452 long int buffer_chr(const buffer * buf, char c)
453 {
454   size_t i;
455 
456   assert(buf);
457   assert(c);
458 
459   for(i=0 ; i < buf->use ; i++) {
460     if (buf->buf[i] == c)
461       return i;
462   }
463 
464   return -1;
465 }
466 
467 
468 /*
469  * Same as buffer_chr but begin by the end of buffer
470  */
buffer_rchr(const buffer * buf,char c)471 long int buffer_rchr(const buffer * buf, char c)
472 {
473   size_t i;
474 
475   assert(buf);
476   assert(c);
477 
478   for(i=buf->use ; i > 0 ; i--) {
479     if (buf->buf[i] == c)
480       return i;
481   }
482 
483   return -1;
484 }
485 
486 
487 /*
488  * Modify string to replace encoded characters by their true value
489  * Function originaly written by Assefa
490  *
491  * The replacements performed are:
492  *  & -> &amp;
493  *  " -> &quot;
494  *  < -> &lt;
495  *  > -> &gt;
496  */
buffer_encode_xml_entities_str(const char * str)497 buffer *buffer_encode_xml_entities_str(const char * str)
498 {
499   buffer *buf;
500 
501   assert(str);
502   buf = buffer_init();
503 
504   for( /* empty */ ; *str ; str++) {
505     switch(*str) {
506       case '&':
507         buffer_add_str(buf, "&amp;");
508         break;
509 
510       case '<':
511         buffer_add_str(buf, "&lt;");
512         break;
513 
514       case '>':
515         buffer_add_str(buf, "&gt;");
516         break;
517 
518       case '"':
519         buffer_add_str(buf, "&quot;");
520         break;
521 
522       case '\'':
523         buffer_add_str(buf, "&#39;");
524         break;
525 
526       default:
527         buffer_add(buf, *str);
528     }
529   }
530 
531   return buf;
532 }
533 
534 
535 /*
536  * Modify string to replace encoded characters by their true value
537  * for JSON output
538  *
539  * The replacements performed are:
540  *  " -> \"
541  */
buffer_encode_json_str(const char * str)542 buffer *buffer_encode_json_str(const char * str)
543 {
544   buffer *buf;
545 
546   assert(str);
547   buf = buffer_init();
548 
549   for( /* empty */ ; *str ; str++) {
550     switch(*str) {
551       case '"':
552         buffer_add_str(buf, "\\\"");
553         break;
554 
555       default:
556         buffer_add(buf, *str);
557     }
558   }
559 
560   return buf;
561 }
562 
563 
564 /*
565  * vim: expandtab sw=4 ts=4
566  */
567