1 /*****
2 *
3 * Copyright (C) 2004-2015 CS-SI. All Rights Reserved.
4 * Author: Yoann Vandoorselaere <yoann.v@prelude-ids.com>
5 *
6 * This file is part of the Prelude library.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 *****/
23 
24 /*
25  * This code include an heavily modified version of the prelude-strbuf
26  * API made by Krzysztof Zaraska, that is now part of prelude-string.
27  */
28 
29 #include "config.h"
30 #include "libmissing.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <assert.h>
37 
38 #include "common.h"
39 #include "prelude-log.h"
40 #include "prelude-inttypes.h"
41 #include "prelude-string.h"
42 
43 
44 #define PRELUDE_ERROR_SOURCE_DEFAULT PRELUDE_ERROR_SOURCE_STRING
45 #include "prelude-error.h"
46 
47 
48 #define CHUNK_SIZE 1024
49 
50 
51 /*
52  * String structure may be free'd
53  */
54 #define PRELUDE_STRING_OWN_STRUCTURE  0x1
55 
56 /*
57  * String data may be free'd
58  */
59 #define PRELUDE_STRING_OWN_DATA       0x2
60 
61 
62 /*
63  * Whether we can reallocate this string
64  */
65 #define PRELUDE_STRING_CAN_REALLOC    0x4
66 
67 
68 
69 
70 #if ! defined (PRELUDE_VA_COPY)
71 
72 # if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
73 #  define PRELUDE_VA_COPY(ap1, ap2)     (*(ap1) = *(ap2))
74 
75 # elif defined (PRELUDE_VA_COPY_AS_ARRAY)
76 #  define PRELUDE_VA_COPY(ap1, ap2)     memmove ((ap1), (ap2), sizeof(va_list))
77 
78 # else /* va_list is a pointer */
79 #  define PRELUDE_VA_COPY(ap1, ap2)     ((ap1) = (ap2))
80 
81 # endif
82 #endif
83 
84 
85 #define STRING_RETURN_IF_INVALID(str, len) do {                                                                \
86         prelude_return_val_if_fail((len + 1) > len,                                                            \
87                                     prelude_error_verbose(PRELUDE_ERROR_INVAL_LENGTH,                          \
88                                                           "string length warning: wrap around would occur"));  \
89                                                                                                                \
90         prelude_return_val_if_fail(str[len] == 0,                                                              \
91                                    prelude_error_verbose(PRELUDE_ERROR_STRING_NOT_NULL_TERMINATED,             \
92                                                          "string warning: not nul terminated"));               \
93 } while(0)
94 
95 
96 
97 struct prelude_string {
98         PRELUDE_LINKED_OBJECT;
99 
100         int flags;
101         int refcount;
102 
103         union {
104                 char *rwbuf;
105                 const char *robuf;
106         } data;
107 
108         size_t size;
109         size_t index;
110 };
111 
112 
string_buf_alloc(prelude_string_t * string,size_t len)113 static int string_buf_alloc(prelude_string_t *string, size_t len)
114 {
115         /*
116          * include room for terminating \0.
117          */
118         string->data.rwbuf = malloc(len + 1);
119         if ( ! string->data.rwbuf )
120                 return prelude_error_from_errno(errno);
121 
122         string->index = len;
123         string->size = len + 1;
124 
125         return 0;
126 }
127 
128 
129 
string_buf_copy(prelude_string_t * string,const char * buf,size_t len)130 static void string_buf_copy(prelude_string_t *string, const char *buf, size_t len)
131 {
132         assert(len < string->size);
133 
134         memcpy(string->data.rwbuf, buf, len);
135         string->data.rwbuf[len] = '\0';
136 }
137 
138 
139 
allocate_more_chunk_if_needed(prelude_string_t * s,size_t needed_len)140 static int allocate_more_chunk_if_needed(prelude_string_t *s, size_t needed_len)
141 {
142         char *ptr;
143         size_t len;
144 
145         if ( needed_len )
146                 len = MAX(needed_len - (s->size - s->index), CHUNK_SIZE);
147         else
148                 len = CHUNK_SIZE;
149 
150         if ( s->size + len < s->size )
151                 return prelude_error(PRELUDE_ERROR_INVAL_LENGTH);
152 
153         if ( s->flags & PRELUDE_STRING_CAN_REALLOC ) {
154 
155                 ptr = _prelude_realloc(s->data.rwbuf, s->size + len);
156                 if ( ! ptr )
157                         return prelude_error_from_errno(errno);
158         }
159 
160         else {
161                 ptr = malloc(s->size + len);
162                 if ( ! ptr )
163                         return prelude_error_from_errno(errno);
164 
165                 if ( s->data.robuf )
166                         memcpy(ptr, s->data.robuf, s->index + 1);
167 
168                 s->flags |= PRELUDE_STRING_CAN_REALLOC|PRELUDE_STRING_OWN_DATA;
169         }
170 
171         s->size += len;
172         s->data.rwbuf = ptr;
173 
174         return 0;
175 }
176 
177 
178 
179 /**
180  * prelude_string_new:
181  * @string: Pointer where to store the created #prelude_string_t.
182  *
183  * Create a new #prelude_string_t object, and store in in @string.
184  *
185  * Returns: 0 on success, or a negative value if an error occured.
186  */
prelude_string_new(prelude_string_t ** string)187 int prelude_string_new(prelude_string_t **string)
188 {
189         *string = calloc(1, sizeof(**string));
190         if ( ! *string )
191                 return prelude_error_from_errno(errno);
192 
193         (*string)->refcount = 1;
194         prelude_list_init(&(*string)->_list);
195         (*string)->flags = PRELUDE_STRING_OWN_STRUCTURE;
196 
197         return 0;
198 }
199 
200 
201 
202 
203 /**
204  * prelude_string_ref:
205  * @string: Pointer to a #prelude_string_t object to reference.
206  *
207  * Increase @string reference count.
208  *
209  * Returns: @string.
210  */
prelude_string_ref(prelude_string_t * string)211 prelude_string_t *prelude_string_ref(prelude_string_t *string)
212 {
213         prelude_return_val_if_fail(string, NULL);
214 
215         string->refcount++;
216         return string;
217 }
218 
219 
220 
221 /**
222  * prelude_string_new_dup_fast:
223  * @string: Pointer where to store the created #prelude_string_t object.
224  * @str: Initial string value.
225  * @len: Lenght of @str.
226  *
227  * Create a new #prelude_string_t object with a copy of @str as it's
228  * initial value.  The copy is owned by the @string and will be freed
229  * upon prelude_string_destroy().
230  *
231  * Returns: 0 on success, a negative value if an error occured.
232  */
prelude_string_new_dup_fast(prelude_string_t ** string,const char * str,size_t len)233 int prelude_string_new_dup_fast(prelude_string_t **string, const char *str, size_t len)
234 {
235         int ret;
236 
237         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
238         STRING_RETURN_IF_INVALID(str, len);
239 
240         ret = prelude_string_new(string);
241         if ( ret < 0 )
242                 return ret;
243 
244         ret = string_buf_alloc(*string, len);
245         if ( ret < 0 )
246                 return ret;
247 
248         string_buf_copy(*string, str, len);
249         (*string)->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
250 
251         return 0;
252 }
253 
254 
255 
256 /**
257  * prelude_string_new_dup:
258  * @string: Pointer where to store the created #prelude_string_t object.
259  * @str: Initial string value.
260  *
261  * Create a new #prelude_string_t object with a copy of @str as it's
262  * initial value. The copy is owned by the @string and will be freed
263  * upon prelude_string_destroy().
264  *
265  * Returns: 0 on success, a negative value if an error occured.
266  */
prelude_string_new_dup(prelude_string_t ** string,const char * str)267 int prelude_string_new_dup(prelude_string_t **string, const char *str)
268 {
269         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
270         return prelude_string_new_dup_fast(string, str, strlen(str));
271 }
272 
273 
274 
275 /**
276  * prelude_string_new_nodup_fast:
277  * @string: Pointer where to store the created #prelude_string_t object.
278  * @str: Initial string value.
279  * @len: Lenght of @str.
280  *
281  * Create a new #prelude_string_t object with a reference to @str as
282  * initial value.  @str is owned by @string and will be freed upon
283  * prelude_string_destroy().
284  *
285  * Returns: 0 on success, a negative value if an error occured.
286  */
prelude_string_new_nodup_fast(prelude_string_t ** string,char * str,size_t len)287 int prelude_string_new_nodup_fast(prelude_string_t **string, char *str, size_t len)
288 {
289         int ret;
290 
291         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
292 
293         STRING_RETURN_IF_INVALID(str, len);
294 
295         ret = prelude_string_new(string);
296         if ( ret < 0 )
297                 return ret;
298 
299         (*string)->index = len;
300         (*string)->size = len + 1;
301         (*string)->data.rwbuf = str;
302         (*string)->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
303 
304         return 0;
305 }
306 
307 
308 
309 /**
310  * prelude_string_new_nodup:
311  * @string: Pointer where to store the created #prelude_string_t object.
312  * @str: Initial string value.
313  *
314  * Create a new #prelude_string_t object with a reference to @str as
315  * initial value.  @str is owned by @string and will be freed upon
316  * prelude_string_destroy().
317  *
318  * Returns: 0 on success, a negative value if an error occured.
319  */
prelude_string_new_nodup(prelude_string_t ** string,char * str)320 int prelude_string_new_nodup(prelude_string_t **string, char *str)
321 {
322         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
323         return prelude_string_new_nodup_fast(string, str, strlen(str));
324 }
325 
326 
327 
328 /**
329  * prelude_string_new_ref_fast:
330  * @string: Pointer where to store the created #prelude_string_t object.
331  * @str: Initial string value.
332  * @len: Length of @str.
333  *
334  * Create a new #prelude_string_t object with a reference to @str as
335  * initial value. @str won't be freed upon prelude_string_destroy().
336  *
337  * Returns: 0 on success, a negative value if an error occured.
338  */
prelude_string_new_ref_fast(prelude_string_t ** string,const char * buf,size_t len)339 int prelude_string_new_ref_fast(prelude_string_t **string, const char *buf, size_t len)
340 {
341         int ret;
342 
343         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
344         STRING_RETURN_IF_INVALID(buf, len);
345 
346         ret = prelude_string_new(string);
347         if ( ret < 0 )
348                 return ret;
349 
350         (*string)->index = len;
351         (*string)->size = len + 1;
352         (*string)->data.robuf = buf;
353 
354         return 0;
355 }
356 
357 
358 
359 /**
360  * prelude_string_new_ref:
361  * @string: Pointer where to store the created #prelude_string_t object.
362  * @str: Initial string value.
363  *
364  * Create a new #prelude_string_t object with a reference to @str as
365  * initial value. @str won't be freed upon prelude_string_destroy().
366  *
367  * Returns: 0 on success, a negative value if an error occured.
368  */
prelude_string_new_ref(prelude_string_t ** string,const char * str)369 int prelude_string_new_ref(prelude_string_t **string, const char *str)
370 {
371         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
372         return prelude_string_new_ref_fast(string, str, strlen(str));
373 }
374 
375 
376 
377 /**
378  * prelude_string_set_dup_fast:
379  * @string: Pointer to a #prelude_string_t object.
380  * @buf: String to store in @string.
381  * @len: Lenght of @buf.
382  *
383  * Store a copy of the string pointed by @buf in @string.
384  * The @buf copy will be freed upon prelude_string_destroy().
385  *
386  * Returns: 0 on success, or a negative value if an error occured.
387  */
prelude_string_set_dup_fast(prelude_string_t * string,const char * buf,size_t len)388 int prelude_string_set_dup_fast(prelude_string_t *string, const char *buf, size_t len)
389 {
390         int ret;
391 
392         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
393         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
394         STRING_RETURN_IF_INVALID(buf, len);
395 
396         prelude_string_destroy_internal(string);
397 
398         ret = string_buf_alloc(string, len);
399         if ( ret < 0 )
400                 return ret;
401 
402         string_buf_copy(string, buf, len);
403         string->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
404 
405         return 0;
406 }
407 
408 
409 
410 /**
411  * prelude_string_set_dup:
412  * @string: Pointer to a #prelude_string_t object.
413  * @buf: String to store in @string.
414  *
415  * Store a copy of the string pointed by @buf in @string.
416  * The @buf copy will be freed upon prelude_string_destroy().
417  *
418  * Returns: 0 on success, or a negative value if an error occured.
419  */
prelude_string_set_dup(prelude_string_t * string,const char * buf)420 int prelude_string_set_dup(prelude_string_t *string, const char *buf)
421 {
422         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
423         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
424         return prelude_string_set_dup_fast(string, buf, strlen(buf));
425 }
426 
427 
428 
429 /**
430  * prelude_string_set_nodup_fast:
431  * @string: Pointer to a #prelude_string_t object.
432  * @buf: String to store in @string.
433  * @len: Lenght of @buf.
434  *
435  * Store a reference to the string pointed by @buf in @string.
436  * The referenced @buf will be freed upon prelude_string_destroy().
437  *
438  * Returns: 0 on success, or a negative value if an error occured.
439  */
prelude_string_set_nodup_fast(prelude_string_t * string,char * buf,size_t len)440 int prelude_string_set_nodup_fast(prelude_string_t *string, char *buf, size_t len)
441 {
442         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
443         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
444         STRING_RETURN_IF_INVALID(buf, len);
445 
446         prelude_string_destroy_internal(string);
447 
448         string->index = len;
449         string->size = len + 1;
450         string->data.rwbuf = buf;
451 
452         string->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
453 
454         return 0;
455 }
456 
457 
458 
459 
460 /**
461  * prelude_string_set_nodup:
462  * @string: Pointer to a #prelude_string_t object.
463  * @buf: String to store in @string.
464  *
465  * Store a reference to the string pointed by @buf in @string.
466  * The referenced @buf will be freed upon prelude_string_destroy().
467  *
468  * Returns: 0 on success, or a negative value if an error occured.
469  */
prelude_string_set_nodup(prelude_string_t * string,char * buf)470 int prelude_string_set_nodup(prelude_string_t *string, char *buf)
471 {
472         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
473         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
474 
475         return prelude_string_set_nodup_fast(string, buf, strlen(buf));
476 }
477 
478 
479 
480 /**
481  * prelude_string_set_ref_fast:
482  * @string: Pointer to a #prelude_string_t object.
483  * @buf: String to store in @string.
484  * @len: Lenght of @buf.
485  *
486  * Store a reference to the string pointed by @buf in @string.
487  * The referenced @buf value won't be modified or freed.
488  *
489  * Returns: 0 on success, or a negative value if an error occured.
490  */
prelude_string_set_ref_fast(prelude_string_t * string,const char * buf,size_t len)491 int prelude_string_set_ref_fast(prelude_string_t *string, const char *buf, size_t len)
492 {
493         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
494         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
495         STRING_RETURN_IF_INVALID(buf, len);
496 
497         prelude_string_destroy_internal(string);
498 
499         string->index = len;
500         string->size = len + 1;
501         string->data.robuf = buf;
502 
503         string->flags &= ~(PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC);
504 
505         return 0;
506 }
507 
508 
509 
510 /**
511  * prelude_string_set_ref:
512  * @string: Pointer to a #prelude_string_t object.
513  * @buf: String to store in @string.
514  *
515  * Store a reference to the string pointed by @buf in @string.
516  * The referenced @buf value won't be modified or freed.
517  *
518  * Returns: 0 on success, or a negative value if an error occured.
519  */
prelude_string_set_ref(prelude_string_t * string,const char * buf)520 int prelude_string_set_ref(prelude_string_t *string, const char *buf)
521 {
522         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
523         prelude_return_val_if_fail(buf, prelude_error(PRELUDE_ERROR_ASSERTION));
524 
525         return prelude_string_set_ref_fast(string, buf, strlen(buf));
526 }
527 
528 
529 
530 
531 /**
532  * prelude_string_copy_ref:
533  * @src: Pointer to a #prelude_string_t object to copy data from.
534  * @dst: Pointer to a #prelude_string_t object to copy data to.
535  *
536  * Reference @src content within @dst.
537  * The referenced content won't be modified or freed.
538  *
539  * Returns: 0 on success, or a negative value if an error occured.
540  */
prelude_string_copy_ref(const prelude_string_t * src,prelude_string_t * dst)541 int prelude_string_copy_ref(const prelude_string_t *src, prelude_string_t *dst)
542 {
543         prelude_return_val_if_fail(src, prelude_error(PRELUDE_ERROR_ASSERTION));
544         prelude_return_val_if_fail(dst, prelude_error(PRELUDE_ERROR_ASSERTION));
545 
546         prelude_string_destroy_internal(dst);
547 
548         dst->size = src->size;
549         dst->index = src->index;
550         dst->data.robuf = src->data.robuf;
551         dst->flags &= ~(PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC);
552 
553         return 0;
554 }
555 
556 
557 
558 /**
559  * prelude_string_copy_dup:
560  * @src: Pointer to a #prelude_string_t object to copy data from.
561  * @dst: Pointer to a #prelude_string_t object to copy data to.
562  *
563  * Copy @src content within @dst.
564  * The content is owned by @src and independent of @dst.
565  *
566  * Returns: 0 on success, or a negative value if an error occured.
567  */
prelude_string_copy_dup(const prelude_string_t * src,prelude_string_t * dst)568 int prelude_string_copy_dup(const prelude_string_t *src, prelude_string_t *dst)
569 {
570         prelude_return_val_if_fail(src, prelude_error(PRELUDE_ERROR_ASSERTION));
571         prelude_return_val_if_fail(dst, prelude_error(PRELUDE_ERROR_ASSERTION));
572 
573         prelude_string_destroy_internal(dst);
574 
575         dst->size = src->size;
576         dst->index = src->index;
577         dst->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
578 
579         if ( src->size ) {
580                 dst->data.rwbuf = malloc(src->size);
581                 if ( ! dst->data.rwbuf )
582                         return prelude_error_from_errno(errno);
583 
584                 string_buf_copy(dst, src->data.robuf, src->index);
585         }
586 
587         return 0;
588 }
589 
590 
591 
592 /**
593  * prelude_string_clone:
594  * @src: Pointer to an existing #prelude_string_t object.
595  * @dst: Pointer to an address where to store the created #prelude_string_t object.
596  *
597  * Clone @src within a new #prelude_string_t object stored into @dst.
598  * Data carried by @dst and @src are independant.
599  *
600  * Returns: 0 on success, or a negative value if an error occured.
601  */
prelude_string_clone(const prelude_string_t * src,prelude_string_t ** dst)602 int prelude_string_clone(const prelude_string_t *src, prelude_string_t **dst)
603 {
604         int ret;
605 
606         prelude_return_val_if_fail(src, prelude_error(PRELUDE_ERROR_ASSERTION));
607 
608         ret = prelude_string_new(dst);
609         if ( ret < 0 )
610                 return ret;
611 
612         (*dst)->size = src->size;
613         (*dst)->index = src->index;
614         (*dst)->flags |= PRELUDE_STRING_OWN_DATA|PRELUDE_STRING_CAN_REALLOC;
615 
616         if ( src->size ) {
617                 (*dst)->data.rwbuf = malloc(src->size);
618                 if ( ! (*dst)->data.rwbuf ) {
619                         prelude_string_destroy(*dst);
620                         return prelude_error_from_errno(errno);
621                 }
622 
623                 string_buf_copy(*dst, src->data.robuf, src->index);
624         }
625 
626         return 0;
627 }
628 
629 
630 
631 /**
632  * prelude_string_get_len:
633  * @string: Pointer to a #prelude_string_t object.
634  *
635  * Return the length of the string carried by @string object.
636  *
637  * Returns: The length of the string owned by @string.
638  */
prelude_string_get_len(const prelude_string_t * string)639 size_t prelude_string_get_len(const prelude_string_t *string)
640 {
641         prelude_return_val_if_fail(string, 0);
642         return string->index;
643 }
644 
645 
646 
647 /**
648  * prelude_string_get_string_or_default:
649  * @string: Pointer to a #prelude_string_t object.
650  * @def: Default value to a return in case @string is empty.
651  *
652  * Return the string carried on by @string object, or @def if it is empty.
653  * There should be no operation done on the returned string since it is still
654  * owned by @string.
655  *
656  * Returns: The string owned by @string or @def.
657  */
prelude_string_get_string_or_default(const prelude_string_t * string,const char * def)658 const char *prelude_string_get_string_or_default(const prelude_string_t *string, const char *def)
659 {
660         prelude_return_val_if_fail(string, NULL);
661         return string->data.robuf ? string->data.robuf : def;
662 }
663 
664 
665 
666 /**
667  * prelude_string_get_string:
668  * @string: Pointer to a #prelude_string_t object.
669  *
670  * Return the string carried on by @string object.
671  * There should be no operation done on the returned string since
672  * it is still owned by @string.
673  *
674  * Returns: The string owned by @string if any.
675  */
prelude_string_get_string(const prelude_string_t * string)676 const char *prelude_string_get_string(const prelude_string_t *string)
677 {
678         prelude_return_val_if_fail(string, NULL);
679         return string->data.robuf;
680 }
681 
682 
683 
684 
685 /**
686  * prelude_string_get_string_released:
687  * @string: Pointer to a #prelude_string_t object.
688  * @outptr: Pointer to an address where to store the released string.
689  *
690  * Get @string content, and release it so that further operation on
691  * @string won't modify the returned content.
692  *
693  * Returns: 0 on success, or a negative value if an error occured.
694  */
prelude_string_get_string_released(prelude_string_t * string,char ** outptr)695 int prelude_string_get_string_released(prelude_string_t *string, char **outptr)
696 {
697         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
698         *outptr = NULL;
699 
700         if ( ! string->index )
701                 return 0;
702 
703         if ( ! (string->flags & PRELUDE_STRING_CAN_REALLOC) ) {
704                 *outptr = strdup(string->data.robuf);
705                 return (*outptr) ? 0 : prelude_error_from_errno(errno);
706         }
707 
708         if ( string->index + 1 <= string->index )
709                 return prelude_error(PRELUDE_ERROR_INVAL_LENGTH);
710 
711         *outptr = _prelude_realloc(string->data.rwbuf, string->index + 1);
712         if ( ! *outptr )
713                 return prelude_error_from_errno(errno);
714 
715         string->size = 0;
716         string->index = 0;
717         string->data.rwbuf = NULL;
718 
719         return 0;
720 }
721 
722 
723 
724 
725 /**
726  * prelude_string_is_empty:
727  * @string: Pointer to a #prelude_string_t object.
728  *
729  * Check whether @string is empty.
730  *
731  * Returns: TRUE if @string is empty, FALSE otherwise.
732  */
prelude_string_is_empty(const prelude_string_t * string)733 prelude_bool_t prelude_string_is_empty(const prelude_string_t *string)
734 {
735         prelude_return_val_if_fail(string, TRUE);
736         return (string->index == 0) ? TRUE : FALSE;
737 }
738 
739 
740 
741 /*
742  *  This function cannot be declared static because its invoked
743  *  from idmef-tree-wrap.c
744  */
prelude_string_destroy_internal(prelude_string_t * string)745 void prelude_string_destroy_internal(prelude_string_t *string)
746 {
747         prelude_return_if_fail(string);
748 
749         if ( (string->flags & PRELUDE_STRING_OWN_DATA) && string->data.rwbuf )
750                 free(string->data.rwbuf);
751 
752         string->data.rwbuf = NULL;
753         string->index = string->size = 0;
754 
755         /*
756          * free() should be done by the caller
757          */
758 }
759 
760 
761 
762 /**
763  * prelude_string_destroy:
764  * @string: Pointer to a #prelude_string_t object.
765  *
766  * Decrease refcount and destroy @string.
767  * @string content content is destroyed if applicable (dup and nodup,
768  * or a referenced string that have been modified.
769  */
prelude_string_destroy(prelude_string_t * string)770 void prelude_string_destroy(prelude_string_t *string)
771 {
772         prelude_return_if_fail(string);
773 
774         if ( --string->refcount )
775                 return;
776 
777         if ( ! prelude_list_is_empty(&string->_list) )
778                 prelude_list_del_init(&string->_list);
779 
780         prelude_string_destroy_internal(string);
781 
782         if ( string->flags & PRELUDE_STRING_OWN_STRUCTURE )
783                 free(string);
784 }
785 
786 
787 
788 
789 /**
790  * prelude_string_vprintf:
791  * @string: Pointer to a #prelude_string_t object.
792  * @fmt: Format string to use.
793  * @ap: Variable argument list.
794  *
795  * Produce output according to @fmt, storing argument provided in @ap
796  * variable argument list, and write the output to the given @string.
797  * See sprintf(3) for more information on @fmt format.
798  *
799  * Returns: The number of characters written, or a negative value if an error occured.
800  */
prelude_string_vprintf(prelude_string_t * string,const char * fmt,va_list ap)801 int prelude_string_vprintf(prelude_string_t *string, const char *fmt, va_list ap)
802 {
803         int ret;
804         va_list bkp;
805 
806         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
807         prelude_return_val_if_fail(fmt, prelude_error(PRELUDE_ERROR_ASSERTION));
808 
809         if ( ! (string->flags & PRELUDE_STRING_CAN_REALLOC) ) {
810 
811                 ret = allocate_more_chunk_if_needed(string, 0);
812                 if ( ret < 0 )
813                         return ret;
814         }
815 
816         PRELUDE_VA_COPY(bkp, ap);
817         ret = vsnprintf(string->data.rwbuf + string->index, string->size - string->index, fmt, ap);
818 
819         /*
820          * From sprintf(3) on GNU/Linux:
821          *
822          * snprintf  and vsnprintf do not write more than
823          * size bytes (including the trailing '\0'), and return -1 if
824          * the  output  was truncated due to this limit.  (Thus until
825          * glibc 2.0.6. Since glibc 2.1 these  functions  follow  the
826          * C99  standard and return the number of characters (exclud-
827          * ing the trailing '\0') which would have  been  written  to
828          * the final string if enough space had been available.)
829          */
830         if ( ret >= 0 && (size_t) ret < string->size - string->index ) {
831                 string->index += ret;
832                 goto end;
833         }
834 
835         ret = allocate_more_chunk_if_needed(string, (ret < 0) ? 0 : ret + 1);
836         if ( ret < 0 )
837                 goto end;
838 
839         ret = prelude_string_vprintf(string, fmt, bkp);
840 
841  end:
842         va_end(bkp);
843         return ret;
844 }
845 
846 
847 
848 
849 /**
850  * prelude_string_sprintf:
851  * @string: Pointer to a #prelude_string_t object.
852  * @fmt: Format string to use.
853  * @...: Variable argument list.
854  *
855  * Produce output according to @fmt, and write output to the given
856  * @string. See snprintf(3) to learn more about @fmt format.
857  *
858  * Returns: The number of characters written, or a negative value if an error occured.
859  */
prelude_string_sprintf(prelude_string_t * string,const char * fmt,...)860 int prelude_string_sprintf(prelude_string_t *string, const char *fmt, ...)
861 {
862         int ret;
863         va_list ap;
864 
865         prelude_return_val_if_fail(string, prelude_error(PRELUDE_ERROR_ASSERTION));
866         prelude_return_val_if_fail(fmt, prelude_error(PRELUDE_ERROR_ASSERTION));
867 
868         va_start(ap, fmt);
869         ret = prelude_string_vprintf(string, fmt, ap);
870         va_end(ap);
871 
872         return ret;
873 }
874 
875 
876 
877 /**
878  * prelude_string_cat:
879  * @dst: Pointer to a #prelude_string_t object.
880  * @str: Pointer to a string.
881  * @len: Length of @str to copy.
882  *
883  * The prelude_string_ncat() function appends @len characters from @str to
884  * the @dst #prelude_string_t object over-writing the `\0' character at the
885  * end of @dst, and then adds a termi-nating `\0' character.
886  *
887  * Returns: @len, or a negative value if an error occured.
888  */
prelude_string_ncat(prelude_string_t * dst,const char * str,size_t len)889 int prelude_string_ncat(prelude_string_t *dst, const char *str, size_t len)
890 {
891         int ret;
892 
893         prelude_return_val_if_fail(dst, prelude_error(PRELUDE_ERROR_ASSERTION));
894         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
895 
896         if ( dst->flags & PRELUDE_STRING_CAN_REALLOC && len < (dst->size - dst->index) ) {
897 
898                 memcpy(dst->data.rwbuf + dst->index, str, len);
899 
900                 dst->index += len;
901                 dst->data.rwbuf[dst->index] = '\0';
902 
903                 return len;
904         }
905 
906         if ( len + 1 < len )
907                 return prelude_error(PRELUDE_ERROR_INVAL_LENGTH);
908 
909         ret = allocate_more_chunk_if_needed(dst, len + 1);
910         if ( ret < 0 )
911                 return ret;
912 
913         return prelude_string_ncat(dst, str, len);
914 }
915 
916 
917 
918 /**
919  * prelude_string_cat:
920  * @dst: Pointer to a #prelude_string_t object.
921  * @str: Pointer to a string.
922  *
923  * The prelude_string_cat() function appends the @str string to the @dst
924  * prelude_string_t object over-writing the `\0' character at the end of
925  * @dst, and then adds a termi-nating `\0' character.
926  *
927  * Returns: @len, or a negative value if an error occured.
928  */
prelude_string_cat(prelude_string_t * dst,const char * str)929 int prelude_string_cat(prelude_string_t *dst, const char *str)
930 {
931         prelude_return_val_if_fail(dst, prelude_error(PRELUDE_ERROR_ASSERTION));
932         prelude_return_val_if_fail(str, prelude_error(PRELUDE_ERROR_ASSERTION));
933 
934         return prelude_string_ncat(dst, str, strlen(str));
935 }
936 
937 
938 
939 
940 /**
941  * prelude_string_clear:
942  * @string: Pointer to a #prelude_string_t object.
943  *
944  * Reset @string content to zero.
945  */
prelude_string_clear(prelude_string_t * string)946 void prelude_string_clear(prelude_string_t *string)
947 {
948         prelude_return_if_fail(string);
949 
950         string->index = 0;
951 
952         if ( string->data.rwbuf && string->flags & PRELUDE_STRING_OWN_DATA )
953                 *(string->data.rwbuf) = '\0';
954 
955         else string->data.rwbuf = NULL;
956 }
957 
958 
959 
960 /**
961  * prelude_string_compare:
962  * @str1: Pointer to a #prelude_string_t object to compare with @str2.
963  * @str2: Pointer to a #prelude_string_t object to compare with @str1.
964  *
965  * Compare @str1 and @str2.
966  *
967  * Returns: 0 if @str1 and @str2 value are equal, a negative value otherwise.
968  */
prelude_string_compare(const prelude_string_t * str1,const prelude_string_t * str2)969 int prelude_string_compare(const prelude_string_t *str1, const prelude_string_t *str2)
970 {
971         if ( ! str1 && ! str2 )
972                 return 0;
973 
974         else if ( ! str1 || ! str2 )
975                 return -1;
976 
977         else if ( str1->index != str2->index )
978                 return -1;
979 
980         if ( str1->index == 0 )
981                 return 0;
982 
983         return strcmp(str1->data.robuf, str2->data.robuf) == 0 ? 0 : -1;
984 }
985