Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * varbuf.c - variable length expandable buffer handling
4 : : *
5 : : * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
7 : : *
8 : : * This 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 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * This 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
19 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <config.h>
23 : : #include <compat.h>
24 : :
25 : : #include <string.h>
26 : : #include <stdlib.h>
27 : : #include <stdio.h>
28 : :
29 : : #include <dpkg/i18n.h>
30 : : #include <dpkg/dpkg.h>
31 : : #include <dpkg/dpkg-db.h>
32 : :
33 : : struct varbuf *
34 : 2 : varbuf_new(size_t size)
35 : : {
36 : : struct varbuf *v;
37 : :
38 : 2 : v = m_malloc(sizeof(*v));
39 : 2 : varbuf_init(v, size);
40 : :
41 : 2 : return v;
42 : : }
43 : :
44 : : void
45 : 201 : varbuf_init(struct varbuf *v, size_t size)
46 : : {
47 : 201 : v->used = 0;
48 : 201 : v->size = size;
49 [ + + ]: 201 : if (size) {
50 : 189 : v->buf = m_malloc(size);
51 : 189 : v->buf[0] = '\0';
52 : : } else {
53 : 12 : v->buf = NULL;
54 : : }
55 : 201 : }
56 : :
57 : : void
58 : 3314 : varbuf_grow(struct varbuf *v, size_t need_size)
59 : : {
60 : : size_t new_size;
61 : :
62 : : /* Make sure the varbuf is in a sane state. */
63 [ - + ]: 3314 : if (v->size < v->used)
64 : 0 : internerr("varbuf used(%zu) > size(%zu)", v->used, v->size);
65 : :
66 : : /* Check if we already have enough room. */
67 [ + + ]: 3314 : if ((v->size - v->used) >= need_size)
68 : 2417 : return;
69 : :
70 : : /* Check if we overflow. */
71 : 897 : new_size = (v->size + need_size) * 2;
72 [ + + ]: 897 : if (new_size < v->size)
73 : 2 : ohshit(_("cannot grow varbuf to size %zu; it would overflow"),
74 : : need_size);
75 : :
76 : 895 : v->size = new_size;
77 : 895 : v->buf = m_realloc(v->buf, v->size);
78 : : }
79 : :
80 : : void
81 : 840 : varbuf_trunc(struct varbuf *v, size_t used_size)
82 : : {
83 : : /* Make sure the caller does not claim more than available. */
84 [ - + ]: 840 : if (v->size < used_size)
85 : 0 : internerr("varbuf new_used(%zu) > size(%zu)", used_size, v->size);
86 : :
87 : 840 : v->used = used_size;
88 [ + - ]: 840 : if (v->buf)
89 : 840 : v->buf[v->used] = '\0';
90 : 840 : }
91 : :
92 : : void
93 : 1322 : varbuf_reset(struct varbuf *v)
94 : : {
95 : 1322 : v->used = 0;
96 [ + + ]: 1322 : if (v->buf)
97 : 1037 : v->buf[0] = '\0';
98 : 1322 : }
99 : :
100 : : const char *
101 : 127 : varbuf_str(struct varbuf *v)
102 : : {
103 [ + + ]: 127 : if (v->buf == NULL)
104 : 11 : return "";
105 : :
106 : 116 : return v->buf;
107 : : }
108 : :
109 : : void
110 : 886 : varbuf_set_buf(struct varbuf *v, const void *buf, size_t size)
111 : : {
112 : 886 : varbuf_reset(v);
113 : 886 : varbuf_add_buf(v, buf, size);
114 : 886 : }
115 : :
116 : : void
117 : 534 : varbuf_set_varbuf(struct varbuf *v, struct varbuf *other)
118 : : {
119 : 534 : varbuf_set_buf(v, other->buf, other->used);
120 : 534 : }
121 : :
122 : : void
123 : 511 : varbuf_add_varbuf(struct varbuf *v, const struct varbuf *other)
124 : : {
125 : 511 : varbuf_grow(v, other->used + 1);
126 : 511 : memcpy(v->buf + v->used, other->buf, other->used);
127 : 511 : v->used += other->used;
128 : 511 : v->buf[v->used] = '\0';
129 : 511 : }
130 : :
131 : : void
132 : 780 : varbuf_add_char(struct varbuf *v, int c)
133 : : {
134 : 780 : varbuf_grow(v, 2);
135 : 780 : v->buf[v->used++] = c;
136 : 780 : v->buf[v->used] = '\0';
137 : 780 : }
138 : :
139 : : void
140 : 2 : varbuf_dup_char(struct varbuf *v, int c, size_t n)
141 : : {
142 [ - + ]: 2 : if (n == 0)
143 : 0 : return;
144 : 2 : varbuf_grow(v, n + 1);
145 : 2 : memset(v->buf + v->used, c, n);
146 : 2 : v->used += n;
147 : 2 : v->buf[v->used] = '\0';
148 : : }
149 : :
150 : : void
151 : 1 : varbuf_map_char(struct varbuf *v, int c_src, int c_dst)
152 : : {
153 : : size_t i;
154 : :
155 [ + + ]: 16 : for (i = 0; i < v->used; i++)
156 [ + + ]: 15 : if (v->buf[i] == c_src)
157 : 3 : v->buf[i] = c_dst;
158 : 1 : }
159 : :
160 : : void
161 : 178 : varbuf_add_dir(struct varbuf *v, const char *dirname)
162 : : {
163 : 178 : varbuf_add_str(v, dirname);
164 [ + + + + ]: 178 : if (v->used == 0 || v->buf[v->used - 1] != '/')
165 : 175 : varbuf_add_char(v, '/');
166 : 178 : }
167 : :
168 : : void
169 : 1576 : varbuf_add_buf(struct varbuf *v, const void *s, size_t size)
170 : : {
171 [ + + ]: 1576 : if (size == 0)
172 : 71 : return;
173 : 1505 : varbuf_grow(v, size + 1);
174 : 1505 : memcpy(v->buf + v->used, s, size);
175 : 1505 : v->used += size;
176 : 1505 : v->buf[v->used] = '\0';
177 : : }
178 : :
179 : : bool
180 : 297 : varbuf_has_prefix(struct varbuf *v, struct varbuf *prefix)
181 : : {
182 [ + + ]: 297 : if (prefix->used > v->used)
183 : 1 : return false;
184 : :
185 [ + + ]: 296 : if (prefix->used == 0)
186 : 25 : return true;
187 [ - + ]: 271 : if (v->used == 0)
188 : 0 : return false;
189 : :
190 : 271 : return strncmp(v->buf, prefix->buf, prefix->used) == 0;
191 : : }
192 : :
193 : : bool
194 : 8 : varbuf_has_suffix(struct varbuf *v, struct varbuf *suffix)
195 : : {
196 : : const char *slice;
197 : :
198 [ + + ]: 8 : if (suffix->used > v->used)
199 : 1 : return false;
200 : :
201 [ + + ]: 7 : if (suffix->used == 0)
202 : 1 : return true;
203 [ - + ]: 6 : if (v->used == 0)
204 : 0 : return false;
205 : :
206 : 6 : slice = v->buf + v->used - suffix->used;
207 : :
208 : 6 : return strcmp(slice, suffix->buf) == 0;
209 : : }
210 : :
211 : : void
212 : 289 : varbuf_trim_varbuf_prefix(struct varbuf *v, struct varbuf *prefix)
213 : : {
214 [ + + ]: 289 : if (!varbuf_has_prefix(v, prefix))
215 : 1 : return;
216 : :
217 : 288 : memmove(v->buf, v->buf + prefix->used, v->used - prefix->used);
218 : 288 : varbuf_trunc(v, v->used - prefix->used);
219 : : }
220 : :
221 : : void
222 : 287 : varbuf_trim_char_prefix(struct varbuf *v, int prefix)
223 : : {
224 : 287 : const char *str = v->buf;
225 : 287 : size_t len = v->used;
226 : :
227 [ + + + - ]: 546 : while (str[0] == prefix && len > 0) {
228 : 259 : str++;
229 : 259 : len--;
230 : : }
231 [ + + ]: 287 : if (str != v->buf) {
232 : 253 : memmove(v->buf, str, len);
233 : 253 : varbuf_trunc(v, len);
234 : : }
235 : 287 : }
236 : :
237 : : int
238 : 465 : varbuf_vprintf(struct varbuf *v, const char *fmt, va_list args)
239 : : {
240 : : va_list args_copy;
241 : : int needed, n;
242 : :
243 : 465 : va_copy(args_copy, args);
244 : 465 : needed = vsnprintf(NULL, 0, fmt, args_copy);
245 : 465 : va_end(args_copy);
246 : :
247 [ - + ]: 465 : if (needed < 0)
248 : 0 : ohshite(_("error formatting string into varbuf variable"));
249 : :
250 : 465 : varbuf_grow(v, needed + 1);
251 : :
252 : 465 : n = vsnprintf(v->buf + v->used, needed + 1, fmt, args);
253 [ - + ]: 465 : if (n < 0)
254 : 0 : ohshite(_("error formatting string into varbuf variable"));
255 : :
256 : 465 : v->used += n;
257 : :
258 : 465 : return n;
259 : : }
260 : :
261 : : int
262 : 311 : varbuf_printf(struct varbuf *v, const char *fmt, ...)
263 : : {
264 : : va_list args;
265 : : int n;
266 : :
267 : 311 : va_start(args, fmt);
268 : 311 : n = varbuf_vprintf(v, fmt, args);
269 : 311 : va_end(args);
270 : :
271 : 311 : return n;
272 : : }
273 : :
274 : : void
275 : 76 : varbuf_snapshot(struct varbuf *v, struct varbuf_state *vs)
276 : : {
277 : 76 : vs->v = v;
278 : 76 : vs->used = v->used;
279 : 76 : }
280 : :
281 : : void
282 : 2 : varbuf_rollback(struct varbuf_state *vs)
283 : : {
284 : 2 : varbuf_trunc(vs->v, vs->used);
285 : 2 : }
286 : :
287 : : size_t
288 : 7 : varbuf_rollback_len(struct varbuf_state *vs)
289 : : {
290 [ - + ]: 7 : if (vs->used > vs->v->used)
291 : 0 : internerr("varbuf state_used(%zu) > used(%zu)",
292 : : vs->used, vs->v->used);
293 : 7 : return vs->v->used - vs->used;
294 : : }
295 : :
296 : : const char *
297 : 14 : varbuf_rollback_start(struct varbuf_state *vs)
298 : : {
299 [ + + ]: 14 : if (vs->v->buf == NULL) {
300 [ - + ]: 2 : if (vs->used)
301 : 0 : internerr("varbuf buf(NULL) state_used(%zu) > 0",
302 : : vs->used);
303 : 2 : return varbuf_str(vs->v);
304 : : }
305 : 12 : return vs->v->buf + vs->used;
306 : : }
307 : :
308 : : char *
309 : 166 : varbuf_detach(struct varbuf *v)
310 : : {
311 : 166 : char *buf = v->buf;
312 : :
313 : 166 : v->buf = NULL;
314 : 166 : v->size = 0;
315 : 166 : v->used = 0;
316 : :
317 [ + + ]: 166 : if (buf == NULL)
318 : 2 : buf = m_strdup("");
319 : :
320 : 166 : return buf;
321 : : }
322 : :
323 : : void
324 : 540 : varbuf_destroy(struct varbuf *v)
325 : : {
326 : 540 : free(v->buf);
327 : 540 : v->buf = NULL;
328 : 540 : v->size = 0;
329 : 540 : v->used = 0;
330 : 540 : }
331 : :
332 : : void
333 : 2 : varbuf_free(struct varbuf *v)
334 : : {
335 : 2 : free(v->buf);
336 : 2 : free(v);
337 : 2 : }
|