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 * & -> &
493 * " -> "
494 * < -> <
495 * > -> >
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, "&");
508 break;
509
510 case '<':
511 buffer_add_str(buf, "<");
512 break;
513
514 case '>':
515 buffer_add_str(buf, ">");
516 break;
517
518 case '"':
519 buffer_add_str(buf, """);
520 break;
521
522 case '\'':
523 buffer_add_str(buf, "'");
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