blob: 80841b24cae972bb666048c09cdbe36d1233b198 [file] [log] [blame]
Damien68f59a92013-10-20 14:39:58 +01001#include <stdio.h>
2#include <stdarg.h>
3#include <string.h>
4#include "misc.h"
5
6// returned value is always at least 1 greater than argument
7#define ROUND_ALLOC(a) (((a) & ((~0) - 7)) + 8)
8
9void vstr_init(vstr_t *vstr) {
10 vstr->alloc = 32;
11 vstr->len = 0;
12 vstr->buf = m_new(char, vstr->alloc);
13 if (vstr->buf == NULL) {
Damien68f59a92013-10-20 14:39:58 +010014 vstr->had_error = true;
15 return;
16 }
17 vstr->buf[0] = 0;
18 vstr->had_error = false;
19}
20
21void vstr_clear(vstr_t *vstr) {
Damien732407f2013-12-29 19:33:23 +000022 m_del(char, vstr->buf, vstr->alloc);
Damien68f59a92013-10-20 14:39:58 +010023 vstr->buf = NULL;
24}
25
Damien8b3a7c22013-10-23 20:20:17 +010026vstr_t *vstr_new(void) {
Damien68f59a92013-10-20 14:39:58 +010027 vstr_t *vstr = m_new(vstr_t, 1);
28 if (vstr == NULL) {
29 return NULL;
30 }
31 vstr_init(vstr);
32 return vstr;
33}
34
35void vstr_free(vstr_t *vstr) {
36 if (vstr != NULL) {
Damien732407f2013-12-29 19:33:23 +000037 m_del(char, vstr->buf, vstr->alloc);
38 m_del_obj(vstr_t, vstr);
Damien68f59a92013-10-20 14:39:58 +010039 }
40}
41
42void vstr_reset(vstr_t *vstr) {
43 vstr->len = 0;
44 vstr->buf[0] = 0;
45 vstr->had_error = false;
46}
47
48bool vstr_had_error(vstr_t *vstr) {
49 return vstr->had_error;
50}
51
52char *vstr_str(vstr_t *vstr) {
53 if (vstr->had_error) {
54 return NULL;
55 }
56 return vstr->buf;
57}
58
59int vstr_len(vstr_t *vstr) {
60 if (vstr->had_error) {
61 return 0;
62 }
63 return vstr->len;
64}
65
66bool vstr_ensure_extra(vstr_t *vstr, int size) {
67 if (vstr->len + size + 1 > vstr->alloc) {
68 int new_alloc = ROUND_ALLOC((vstr->len + size + 1) * 2);
Damien732407f2013-12-29 19:33:23 +000069 char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc);
Damien68f59a92013-10-20 14:39:58 +010070 if (new_buf == NULL) {
71 vstr->had_error = true;
72 return false;
73 }
74 vstr->alloc = new_alloc;
75 vstr->buf = new_buf;
76 }
77 return true;
78}
79
80void vstr_hint_size(vstr_t *vstr, int size) {
81 // it's not an error if we fail to allocate for the size hint
82 bool er = vstr->had_error;
83 vstr_ensure_extra(vstr, size);
84 vstr->had_error = er;
85}
86
87char *vstr_add_len(vstr_t *vstr, int len) {
88 if (vstr->had_error || !vstr_ensure_extra(vstr, len)) {
89 return NULL;
90 }
91 char *buf = vstr->buf + vstr->len;
92 vstr->len += len;
93 vstr->buf[vstr->len] = 0;
94 return buf;
95}
96
97void vstr_add_byte(vstr_t *vstr, byte v) {
98 byte *buf = (byte*)vstr_add_len(vstr, 1);
99 if (buf == NULL) {
100 return;
101 }
102 buf[0] = v;
103}
104
105void vstr_add_char(vstr_t *vstr, unichar c) {
106 // TODO UNICODE
107 byte *buf = (byte*)vstr_add_len(vstr, 1);
108 if (buf == NULL) {
109 return;
110 }
111 buf[0] = c;
112}
113
114void vstr_add_str(vstr_t *vstr, const char *str) {
115 vstr_add_strn(vstr, str, strlen(str));
116}
117
118void vstr_add_strn(vstr_t *vstr, const char *str, int len) {
119 if (vstr->had_error || !vstr_ensure_extra(vstr, len)) {
120 return;
121 }
122 memmove(vstr->buf + vstr->len, str, len);
123 vstr->len += len;
124 vstr->buf[vstr->len] = 0;
125}
126
127/*
128void vstr_add_le16(vstr_t *vstr, unsigned short v) {
129 byte *buf = (byte*)vstr_add_len(vstr, 2);
130 if (buf == NULL) {
131 return;
132 }
133 encode_le16(buf, v);
134}
135
136void vstr_add_le32(vstr_t *vstr, unsigned int v) {
137 byte *buf = (byte*)vstr_add_len(vstr, 4);
138 if (buf == NULL) {
139 return;
140 }
141 encode_le32(buf, v);
142}
143*/
144
145void vstr_cut_tail(vstr_t *vstr, int len) {
146 if (vstr->had_error) {
147 return;
148 }
149 if (len > vstr->len) {
150 vstr->len = 0;
151 } else {
152 vstr->len -= len;
153 }
154}
155
Damien68f59a92013-10-20 14:39:58 +0100156void vstr_printf(vstr_t *vstr, const char *fmt, ...) {
Damien2f06c572013-11-03 18:20:56 +0000157 va_list ap;
158 va_start(ap, fmt);
159 vstr_vprintf(vstr, fmt, ap);
160 va_end(ap);
161}
162
163void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap) {
Damien68f59a92013-10-20 14:39:58 +0100164 if (vstr->had_error || !vstr_ensure_extra(vstr, strlen(fmt))) {
165 return;
166 }
167
168 while (1) {
169 // try to print in the allocated space
Damien George66028ab2014-01-03 14:03:48 +0000170 // need to make a copy of the va_list because we may call vsnprintf multiple times
Damien68f59a92013-10-20 14:39:58 +0100171 int size = vstr->alloc - vstr->len;
Damien George66028ab2014-01-03 14:03:48 +0000172 va_list ap2;
173 va_copy(ap2, ap);
174 int n = vsnprintf(vstr->buf + vstr->len, size, fmt, ap2);
175 va_end(ap2);
Damien68f59a92013-10-20 14:39:58 +0100176
177 // if that worked, return
178 if (n > -1 && n < size) {
179 vstr->len += n;
180 return;
181 }
182
183 // else try again with more space
184 if (n > -1) { // glibc 2.1
185 // n + 1 is precisely what is needed
186 if (!vstr_ensure_extra(vstr, n + 1)) {
187 return;
188 }
189 } else { // glibc 2.0
190 // increase to twice the old size
191 if (!vstr_ensure_extra(vstr, size * 2)) {
192 return;
193 }
194 }
195 }
196}
Damien68f59a92013-10-20 14:39:58 +0100197
198/** testing *****************************************************/
199
200/*
Damien8b3a7c22013-10-23 20:20:17 +0100201int main(void) {
Damien68f59a92013-10-20 14:39:58 +0100202 vstr_t *vstr = vstr_new();
203 int i;
204 for (i = 0; i < 10; i++) {
205 vstr_printf(vstr, "%d) this is a test %d %s\n", i, 1234, "'a string'");
206 vstr_add_str(vstr, "-----");
207 vstr_printf(vstr, "this is another test %d %s\n", 1234, "'a second string'");
208 printf("%s", vstr->buf);
209 }
210}
211*/