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 : : void
34 : 240 : varbuf_add_char(struct varbuf *v, int c)
35 : : {
36 : 240 : varbuf_grow(v, 1);
37 : 240 : v->buf[v->used++]= c;
38 : 240 : }
39 : :
40 : : void
41 : 2 : varbuf_dup_char(struct varbuf *v, int c, size_t n)
42 : : {
43 [ - + ]: 2 : if (n == 0)
44 : 0 : return;
45 : 2 : varbuf_grow(v, n);
46 : 2 : memset(v->buf + v->used, c, n);
47 : 2 : v->used += n;
48 : : }
49 : :
50 : : void
51 : 1 : varbuf_map_char(struct varbuf *v, int c_src, int c_dst)
52 : : {
53 : : size_t i;
54 : :
55 [ + + ]: 16 : for (i = 0; i < v->used; i++)
56 [ + + ]: 15 : if (v->buf[i] == c_src)
57 : 3 : v->buf[i] = c_dst;
58 : 1 : }
59 : :
60 : : int
61 : 255 : varbuf_printf(struct varbuf *v, const char *fmt, ...)
62 : : {
63 : : int r;
64 : : va_list args;
65 : :
66 : 255 : va_start(args, fmt);
67 : 255 : r = varbuf_vprintf(v, fmt, args);
68 : 255 : va_end(args);
69 : :
70 : 255 : return r;
71 : : }
72 : :
73 : : int
74 : 382 : varbuf_vprintf(struct varbuf *v, const char *fmt, va_list args)
75 : : {
76 : : va_list args_copy;
77 : : int needed, r;
78 : :
79 : 382 : va_copy(args_copy, args);
80 : 382 : needed = vsnprintf(NULL, 0, fmt, args_copy);
81 : 382 : va_end(args_copy);
82 : :
83 [ - + ]: 382 : if (needed < 0)
84 : 0 : ohshite(_("error formatting string into varbuf variable"));
85 : :
86 : 382 : varbuf_grow(v, needed + 1);
87 : :
88 : 382 : r = vsnprintf(v->buf + v->used, needed + 1, fmt, args);
89 [ - + ]: 382 : if (r < 0)
90 : 0 : ohshite(_("error formatting string into varbuf variable"));
91 : :
92 : 382 : v->used += r;
93 : :
94 : 382 : return r;
95 : : }
96 : :
97 : : void
98 : 814 : varbuf_add_buf(struct varbuf *v, const void *s, size_t size)
99 : : {
100 [ + + ]: 814 : if (size == 0)
101 : 5 : return;
102 : 809 : varbuf_grow(v, size);
103 : 809 : memcpy(v->buf + v->used, s, size);
104 : 809 : v->used += size;
105 : : }
106 : :
107 : : void
108 : 178 : varbuf_add_dir(struct varbuf *v, const char *dirname)
109 : : {
110 : 178 : varbuf_add_str(v, dirname);
111 [ + + + + ]: 178 : if (v->used == 0 || v->buf[v->used - 1] != '/')
112 : 175 : varbuf_add_char(v, '/');
113 : 178 : }
114 : :
115 : : void
116 : 551 : varbuf_end_str(struct varbuf *v)
117 : : {
118 : 551 : varbuf_grow(v, 1);
119 : 551 : v->buf[v->used] = '\0';
120 : 551 : }
121 : :
122 : : const char *
123 : 2 : varbuf_get_str(struct varbuf *v)
124 : : {
125 : 2 : varbuf_end_str(v);
126 : :
127 : 2 : return v->buf;
128 : : }
129 : :
130 : : struct varbuf *
131 : 2 : varbuf_new(size_t size)
132 : : {
133 : : struct varbuf *v;
134 : :
135 : 2 : v = m_malloc(sizeof(*v));
136 : 2 : varbuf_init(v, size);
137 : :
138 : 2 : return v;
139 : : }
140 : :
141 : : void
142 : 98 : varbuf_init(struct varbuf *v, size_t size)
143 : : {
144 : 98 : v->used = 0;
145 : 98 : v->size = size;
146 [ + + ]: 98 : if (size)
147 : 89 : v->buf = m_malloc(size);
148 : : else
149 : 9 : v->buf = NULL;
150 : 98 : }
151 : :
152 : : void
153 : 529 : varbuf_reset(struct varbuf *v)
154 : : {
155 : 529 : v->used= 0;
156 : 529 : }
157 : :
158 : : void
159 : 1998 : varbuf_grow(struct varbuf *v, size_t need_size)
160 : : {
161 : : size_t new_size;
162 : :
163 : : /* Make sure the varbuf is in a sane state. */
164 [ - + ]: 1998 : if (v->size < v->used)
165 : 0 : internerr("varbuf used(%zu) > size(%zu)", v->used, v->size);
166 : :
167 : : /* Check if we already have enough room. */
168 [ + + ]: 1998 : if ((v->size - v->used) >= need_size)
169 : 1363 : return;
170 : :
171 : : /* Check if we overflow. */
172 : 635 : new_size = (v->size + need_size) * 2;
173 [ + + ]: 635 : if (new_size < v->size)
174 : 2 : ohshit(_("cannot grow varbuf to size %zu; it would overflow"), need_size);
175 : :
176 : 633 : v->size = new_size;
177 : 633 : v->buf = m_realloc(v->buf, v->size);
178 : : }
179 : :
180 : : void
181 : 5 : varbuf_trunc(struct varbuf *v, size_t used_size)
182 : : {
183 : : /* Make sure the caller does not claim more than available. */
184 [ - + ]: 5 : if (v->size < used_size)
185 : 0 : internerr("varbuf new_used(%zu) > size(%zu)", used_size, v->size);
186 : :
187 : 5 : v->used = used_size;
188 : 5 : }
189 : :
190 : : void
191 : 76 : varbuf_snapshot(struct varbuf *v, struct varbuf_state *vs)
192 : : {
193 : 76 : vs->v = v;
194 : 76 : vs->used = v->used;
195 : 76 : }
196 : :
197 : : void
198 : 2 : varbuf_rollback(struct varbuf_state *vs)
199 : : {
200 : 2 : varbuf_trunc(vs->v, vs->used);
201 : 2 : }
202 : :
203 : : size_t
204 : 7 : varbuf_rollback_len(struct varbuf_state *vs)
205 : : {
206 [ - + ]: 7 : if (vs->used > vs->v->used)
207 : 0 : internerr("varbuf state_used(%zu) > used(%zu)", vs->used, vs->v->used);
208 : 7 : return vs->v->used - vs->used;
209 : : }
210 : :
211 : : const char *
212 : 14 : varbuf_rollback_start(struct varbuf_state *vs)
213 : : {
214 [ + + ]: 14 : if (vs->v->buf == NULL) {
215 [ - + ]: 2 : if (vs->used)
216 : 0 : internerr("varbuf buf(NULL) state_used(%zu) > 0", vs->used);
217 : : /* XXX: Ideally this would be handled by varbuf always having a valid
218 : : * buf or switching all users to the getter, but for now this will do. */
219 : 2 : return "";
220 : : }
221 : 12 : return vs->v->buf + vs->used;
222 : : }
223 : :
224 : : char *
225 : 140 : varbuf_detach(struct varbuf *v)
226 : : {
227 : 140 : char *buf = v->buf;
228 : :
229 : 140 : v->buf = NULL;
230 : 140 : v->size = 0;
231 : 140 : v->used = 0;
232 : :
233 : 140 : return buf;
234 : : }
235 : :
236 : : void
237 : 301 : varbuf_destroy(struct varbuf *v)
238 : : {
239 : 301 : free(v->buf); v->buf=NULL; v->size=0; v->used=0;
240 : 301 : }
241 : :
242 : : void
243 : 2 : varbuf_free(struct varbuf *v)
244 : : {
245 : 2 : free(v->buf);
246 : 2 : free(v);
247 : 2 : }
|