aboutsummaryrefslogtreecommitdiff
path: root/strbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'strbuf.c')
-rw-r--r--strbuf.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/strbuf.c b/strbuf.c
new file mode 100644
index 0000000..f823884
--- /dev/null
+++ b/strbuf.c
@@ -0,0 +1,130 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <stdarg.h>
4#include <string.h>
5
6#include "strbuf.h"
7
8static void die(const char *format, ...)
9{
10 va_list arg;
11
12 va_start(arg, format);
13 vfprintf(stderr, format, arg);
14 va_end(arg);
15
16 exit(-1);
17}
18
19void strbuf_init(strbuf_t *s)
20{
21 s->data = NULL;
22 s->size = 0;
23 s->length = 0;
24 s->increment = STRBUF_DEFAULT_INCREMENT;
25}
26
27strbuf_t *strbuf_new()
28{
29 strbuf_t *s;
30
31 s = malloc(sizeof(strbuf_t));
32 if (!s)
33 die("Out of memory");
34
35 strbuf_init(s);
36
37 return s;
38}
39
40void strbuf_set_increment(strbuf_t *s, int increment)
41{
42 if (increment <= 0)
43 die("BUG: Invalid string increment");
44
45 s->increment = increment;
46}
47
48void strbuf_free(strbuf_t *s)
49{
50 if (s->data)
51 free(s->data);
52 free(s);
53}
54
55char *strbuf_to_char(strbuf_t *s, int *len)
56{
57 char *data;
58
59 data = s->data;
60 if (len)
61 *len = s->length;
62
63 free(s);
64
65 return data;
66}
67
68/* Ensure strbuf can handle a string length bytes long (ignoring NULL
69 * optional termination). */
70void strbuf_resize(strbuf_t *s, int len)
71{
72 int newsize;
73
74 /* Esnure there is room for optional NULL termination */
75 newsize = len + 1;
76 /* Round up to the next increment */
77 newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
78 s->size = newsize;
79 s->data = realloc(s->data, s->size);
80 if (!s->data)
81 die("Out of memory");
82}
83
84void strbuf_append_mem(strbuf_t *s, const char *c, int len)
85{
86 if (len > strbuf_emptylen(s))
87 strbuf_resize(s, s->length + len);
88
89 memcpy(s->data + s->length, c, len);
90 s->length += len;
91}
92
93void strbuf_ensure_null(strbuf_t *s)
94{
95 s->data[s->length] = 0;
96}
97
98void strbuf_append_fmt(strbuf_t *s, const char *fmt, ...)
99{
100 va_list arg;
101 int fmt_len, try;
102 int empty_len;
103
104 /* If the first attempt to append fails, resize the buffer appropriately
105 * and try again */
106 for (try = 0; ; try++) {
107 va_start(arg, fmt);
108 /* Append the new formatted string */
109 /* fmt_len is the length of the string required, excluding the
110 * trailing NULL */
111 empty_len = strbuf_emptylen(s);
112 /* Add 1 since there is also space for the terminating NULL.
113 * If the string hasn't been allocated then empty_len == -1,
114 * and vsprintf() won't store anything on the first pass */
115 fmt_len = vsnprintf(s->data + s->length, empty_len + 1, fmt, arg);
116 va_end(arg);
117
118 if (fmt_len <= empty_len)
119 break; /* SUCCESS */
120 if (try > 0)
121 die("BUG: length of formatted string changed");
122
123 strbuf_resize(s, s->length + fmt_len);
124 }
125
126 s->length += fmt_len;
127}
128
129/* vi:ai et sw=4 ts=4:
130 */