Commit | Line | Data |
---|---|---|
800d4c59 | 1 | /* -*-c-*- |
2 | * | |
800d4c59 | 3 | * Buffer handling |
4 | * | |
5 | * (c) 2001 Straylight/Edgeware | |
6 | */ | |
7 | ||
d4efbcd9 | 8 | /*----- Licensing notice --------------------------------------------------* |
800d4c59 | 9 | * |
9b5ac6ff | 10 | * This file is part of the mLib utilities library. |
800d4c59 | 11 | * |
9b5ac6ff | 12 | * mLib is free software; you can redistribute it and/or modify |
800d4c59 | 13 | * it under the terms of the GNU Library General Public License as |
14 | * published by the Free Software Foundation; either version 2 of the | |
15 | * License, or (at your option) any later version. | |
d4efbcd9 | 16 | * |
9b5ac6ff | 17 | * mLib is distributed in the hope that it will be useful, |
800d4c59 | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU Library General Public License for more details. | |
d4efbcd9 | 21 | * |
800d4c59 | 22 | * You should have received a copy of the GNU Library General Public |
9b5ac6ff | 23 | * License along with mLib; if not, write to the Free |
800d4c59 | 24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
25 | * MA 02111-1307, USA. | |
26 | */ | |
27 | ||
28 | /*----- Header files ------------------------------------------------------*/ | |
29 | ||
9b5ac6ff | 30 | #include <assert.h> |
800d4c59 | 31 | #include <string.h> |
32 | ||
800d4c59 | 33 | #include "buf.h" |
0d61a23c | 34 | #include "macros.h" |
800d4c59 | 35 | |
36 | /*----- Main code ---------------------------------------------------------*/ | |
37 | ||
38 | /* --- @buf_init@ --- * | |
39 | * | |
40 | * Arguments: @buf *b@ = pointer to a buffer block | |
41 | * @void *p@ = pointer to a buffer | |
42 | * @size_t sz@ = size of the buffer | |
43 | * | |
44 | * Returns: --- | |
45 | * | |
46 | * Use: Initializes the buffer block appropriately. | |
47 | */ | |
48 | ||
49 | void buf_init(buf *b, void *p, size_t sz) | |
50 | { | |
51 | b->base = b->p = p; | |
52 | b->limit = b->p + sz; | |
53 | b->f = 0; | |
54 | } | |
55 | ||
56 | /* --- @buf_break@ --- * | |
57 | * | |
58 | * Arguments: @buf *b@ = pointer to a buffer block | |
59 | * | |
60 | * Returns: Some negative value. | |
61 | * | |
62 | * Use: Marks a buffer as broken. | |
63 | */ | |
64 | ||
65 | int buf_break(buf *b) { b->f |= BF_BROKEN; return (-1); } | |
66 | ||
67 | /* --- @buf_flip@ --- * | |
68 | * | |
69 | * Arguments: @buf *b@ = pointer to a buffer block | |
70 | * | |
71 | * Returns: --- | |
72 | * | |
73 | * Use: Flips a buffer so that if you've just been writing to it, | |
74 | * you can now read from the bit you've written. | |
75 | */ | |
76 | ||
77 | void buf_flip(buf *b) | |
78 | { | |
79 | b->limit = b->p; | |
80 | b->p = b->base; | |
81 | } | |
82 | ||
83 | /* --- @buf_ensure@ --- * | |
84 | * | |
85 | * Arguments: @buf *b@ = pointer to a buffer block | |
86 | * @size_t sz@ = size of data wanted | |
87 | * | |
88 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
89 | * | |
90 | * Use: Ensures that there are @sz@ bytes still in the buffer. | |
91 | */ | |
92 | ||
93 | int buf_ensure(buf *b, size_t sz) { return (BENSURE(b, sz)); } | |
94 | ||
95 | /* --- @buf_get@ --- * | |
96 | * | |
97 | * Arguments: @buf *b@ = pointer to a buffer block | |
98 | * @size_t sz@ = size of the buffer | |
99 | * | |
100 | * Returns: Pointer to the place in the buffer. | |
101 | * | |
102 | * Use: Reserves a space in the buffer of the requested size, and | |
103 | * returns its start address. | |
104 | */ | |
105 | ||
106 | void *buf_get(buf *b, size_t sz) | |
107 | { | |
108 | void *p; | |
109 | if (BENSURE(b, sz)) | |
110 | return (0); | |
111 | p = BCUR(b); | |
112 | BSTEP(b, sz); | |
113 | return (p); | |
114 | } | |
115 | ||
116 | /* --- @buf_put@ --- * | |
117 | * | |
118 | * Arguments: @buf *b@ = pointer to a buffer block | |
119 | * @const void *p@ = pointer to a buffer | |
120 | * @size_t sz@ = size of the buffer | |
121 | * | |
122 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
123 | * | |
124 | * Use: Fetches data from some place and puts it in the buffer | |
125 | */ | |
126 | ||
127 | int buf_put(buf *b, const void *p, size_t sz) | |
128 | { | |
129 | if (BENSURE(b, sz)) | |
130 | return (-1); | |
131 | memcpy(BCUR(b), p, sz); | |
132 | BSTEP(b, sz); | |
133 | return (0); | |
134 | } | |
135 | ||
136 | /* --- @buf_getbyte@ --- * | |
137 | * | |
138 | * Arguments: @buf *b@ = pointer to a buffer block | |
139 | * | |
140 | * Returns: A byte, or less than zero if there wasn't a byte there. | |
141 | * | |
142 | * Use: Gets a single byte from a buffer. | |
143 | */ | |
144 | ||
145 | int buf_getbyte(buf *b) | |
146 | { | |
147 | if (BENSURE(b, 1)) | |
148 | return (-1); | |
149 | return (*b->p++); | |
150 | } | |
151 | ||
152 | /* --- @buf_putbyte@ --- * | |
153 | * | |
154 | * Arguments: @buf *b@ = pointer to a buffer block | |
155 | * @int ch@ = byte to write | |
156 | * | |
157 | * Returns: Zero if OK, nonzero if there wasn't enough space. | |
158 | * | |
159 | * Use: Puts a single byte in a buffer. | |
160 | */ | |
161 | ||
162 | int buf_putbyte(buf *b, int ch) | |
163 | { | |
164 | if (BENSURE(b, 1)) | |
165 | return (-1); | |
166 | *b->p++ = ch; | |
167 | return (0); | |
168 | } | |
169 | ||
9b5ac6ff | 170 | /* --- @buf_getu{8,{16,24,32,64}{,l,b}}@ --- * |
800d4c59 | 171 | * |
172 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 173 | * @uintSZ *w@ = where to put the word |
800d4c59 | 174 | * |
175 | * Returns: Zero if OK, or nonzero if there wasn't a word there. | |
176 | * | |
9b5ac6ff | 177 | * Use: Gets a word of appropriate size and order from a buffer. |
800d4c59 | 178 | */ |
179 | ||
9b5ac6ff | 180 | #define BUF_GETU_(n, W, w) \ |
181 | int buf_getu##w(buf *b, uint##n *ww) \ | |
182 | { \ | |
183 | if (BENSURE(b, SZ_##W)) return (-1); \ | |
184 | *ww = LOAD##W(b->p); \ | |
185 | BSTEP(b, SZ_##W); \ | |
186 | return (0); \ | |
187 | } | |
188 | DOUINTCONV(BUF_GETU_) | |
800d4c59 | 189 | |
b64eb60f MW |
190 | /* --- @buf_getk64{,l,b}@ --- * |
191 | * | |
192 | * Arguments: @buf *b@ = pointer to a buffer block | |
193 | * @kludge64 *w@ = where to put the word | |
194 | * | |
195 | * Returns: Zero if OK, or nonzero if there wasn't a word there. | |
196 | * | |
197 | * Use: Gets a word of appropriate size and order from a buffer. | |
198 | */ | |
199 | ||
200 | int buf_getk64(buf *b, kludge64 *w) | |
201 | { | |
202 | if (BENSURE(b, 8)) return (-1); | |
203 | LOAD64_(*w, b->p); BSTEP(b, 8); return (0); | |
204 | } | |
205 | ||
206 | int buf_getk64l(buf *b, kludge64 *w) | |
207 | { | |
208 | if (BENSURE(b, 8)) return (-1); | |
209 | LOAD64_L_(*w, b->p); BSTEP(b, 8); return (0); | |
210 | } | |
211 | ||
212 | int buf_getk64b(buf *b, kludge64 *w) | |
213 | { | |
214 | if (BENSURE(b, 8)) return (-1); | |
215 | LOAD64_B_(*w, b->p); BSTEP(b, 8); return (0); | |
216 | } | |
217 | ||
9b5ac6ff | 218 | /* --- @buf_putu{8,{16,24,32,64}{,l,b}}@ --- * |
800d4c59 | 219 | * |
220 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 221 | * @uintSZ w@ = word to write |
800d4c59 | 222 | * |
9b5ac6ff | 223 | * Returns: Zero if OK, or nonzero if there wasn't enough space |
800d4c59 | 224 | * |
9b5ac6ff | 225 | * Use: Puts a word into a buffer with appropriate size and order. |
800d4c59 | 226 | */ |
227 | ||
9b5ac6ff | 228 | #define BUF_PUTU_(n, W, w) \ |
229 | int buf_putu##w(buf *b, uint##n ww) \ | |
230 | { \ | |
231 | if (BENSURE(b, SZ_##W)) return (-1); \ | |
232 | STORE##W(b->p, ww); \ | |
233 | BSTEP(b, SZ_##W); \ | |
234 | return (0); \ | |
235 | } | |
236 | DOUINTCONV(BUF_PUTU_) | |
800d4c59 | 237 | |
b64eb60f MW |
238 | /* --- @buf_putk64{,l,b}@ --- * |
239 | * | |
240 | * Arguments: @buf *b@ = pointer to a buffer block | |
241 | * @kludge64 w@ = word to write | |
242 | * | |
243 | * Returns: Zero if OK, or nonzero if there wasn't enough space | |
244 | * | |
245 | * Use: Gets a word of appropriate size and order from a buffer. | |
246 | */ | |
247 | ||
248 | int buf_putk64(buf *b, kludge64 w) | |
249 | { | |
250 | if (BENSURE(b, 8)) return (-1); | |
251 | STORE64_(b->p, w); BSTEP(b, 8); return (0); | |
252 | } | |
253 | ||
254 | int buf_putk64l(buf *b, kludge64 w) | |
255 | { | |
256 | if (BENSURE(b, 8)) return (-1); | |
257 | STORE64_L_(b->p, w); BSTEP(b, 8); return (0); | |
258 | } | |
259 | ||
260 | int buf_putk64b(buf *b, kludge64 w) | |
261 | { | |
262 | if (BENSURE(b, 8)) return (-1); | |
263 | STORE64_B_(b->p, w); BSTEP(b, 8); return (0); | |
264 | } | |
265 | ||
800d4c59 | 266 | /* --- @findz@ --- * |
267 | * | |
268 | * Arguments: @buf *b@ = pointer to a buffer block | |
269 | * @size_t *nn@ = where to put the length | |
270 | * | |
271 | * Returns: Zero if OK, nonzero if there wasn't a null byte to be found. | |
272 | * | |
95491579 MW |
273 | * Use: Finds a terminating null byte. The length includes this |
274 | * terminator. | |
800d4c59 | 275 | */ |
276 | ||
277 | static int findz(buf *b, size_t *nn) | |
278 | { | |
279 | octet *p; | |
280 | ||
a4589237 | 281 | if ((p = memchr(BCUR(b), 0, BLEFT(b))) == 0) { |
800d4c59 | 282 | buf_break(b); |
283 | return (-1); | |
284 | } | |
95491579 | 285 | *nn = p - BCUR(b) + 1; |
800d4c59 | 286 | return (0); |
287 | } | |
288 | ||
9b5ac6ff | 289 | /* --- @buf_getmem{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 290 | * |
291 | * Arguments: @buf *b@ = pointer to a buffer block | |
292 | * @size_t *nn@ = where to put the length | |
293 | * | |
294 | * Returns: Pointer to the buffer data, or null. | |
295 | * | |
9b5ac6ff | 296 | * Use: Gets a chunk of memory from a buffer. The suffix is the |
297 | * width and byte order of the length; @z@ means null- | |
298 | * terminated. | |
800d4c59 | 299 | */ |
300 | ||
9b5ac6ff | 301 | #define BUF_GETMEM_(n, W, w) \ |
302 | void *buf_getmem##w(buf *b, size_t *nn) \ | |
303 | { \ | |
304 | uint##n sz; \ | |
a4589237 | 305 | if (buf_getu##w(b, &sz)) return (0); \ |
f868c432 | 306 | if (BENSURE(b, sz)) return (0); \ |
9b5ac6ff | 307 | *nn = sz; \ |
308 | return (buf_get(b, sz)); \ | |
309 | } | |
310 | DOUINTCONV(BUF_GETMEM_) | |
800d4c59 | 311 | |
800d4c59 | 312 | void *buf_getmemz(buf *b, size_t *nn) |
313 | { | |
314 | if (findz(b, nn)) return (0); | |
315 | return (buf_get(b, *nn)); | |
316 | } | |
317 | ||
9b5ac6ff | 318 | /* --- @buf_putmem{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 319 | * |
320 | * Arguments: @buf *b@ = pointer to a buffer block | |
321 | * @const void *p@ = pointer to data to write | |
322 | * @size_t n@ = length to write | |
323 | * | |
324 | * Returns: Zero if OK, nonzero if there wasn't enough space. | |
325 | * | |
9b5ac6ff | 326 | * Use: Writes a chunk of data to a buffer. The suffix is the |
327 | * width and byte order of the length; @z@ means null- | |
328 | * terminated. | |
800d4c59 | 329 | */ |
330 | ||
9b5ac6ff | 331 | #define BUF_PUTMEM_(n, W, w) \ |
332 | int buf_putmem##w(buf *b, const void *p, size_t sz) \ | |
333 | { \ | |
0d61a23c MW |
334 | MUFFLE_WARNINGS_STMT \ |
335 | (CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \ | |
336 | { assert(sz <= MASK##W); }); \ | |
a4589237 | 337 | if (buf_putu##w(b, sz) || buf_put(b, p, sz)) \ |
9b5ac6ff | 338 | return (-1); \ |
339 | return (0); \ | |
340 | } | |
341 | DOUINTCONV(BUF_PUTMEM_) | |
800d4c59 | 342 | |
343 | int buf_putmemz(buf *b, const void *p, size_t n) | |
344 | { | |
345 | octet *q; | |
346 | ||
347 | assert(!memchr(p, 0, n)); | |
348 | if ((q = buf_get(b, n + 1)) == 0) | |
349 | return (-1); | |
350 | memcpy(q, p, n); | |
351 | q[n] = 0; | |
352 | return (0); | |
353 | } | |
354 | ||
9b5ac6ff | 355 | /* --- @buf_getbuf{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 356 | * |
357 | * Arguments: @buf *b@ = pointer to a buffer block | |
358 | * @buf *bb@ = where to put the result | |
359 | * | |
360 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
361 | * | |
362 | * Use: Gets a block of data from a buffer, and writes its bounds to | |
9b5ac6ff | 363 | * another buffer. |
800d4c59 | 364 | */ |
365 | ||
9b5ac6ff | 366 | #define BUF_GETBUF_(n, W, w) \ |
367 | int buf_getbuf##w(buf *b, buf *bb) \ | |
368 | { \ | |
369 | void *p; \ | |
370 | size_t sz; \ | |
800d4c59 | 371 | \ |
9b5ac6ff | 372 | if ((p = buf_getmem##w(b, &sz)) == 0) \ |
373 | return (-1); \ | |
374 | buf_init(bb, p, sz); \ | |
375 | return (0); \ | |
800d4c59 | 376 | } |
9b5ac6ff | 377 | BUF_DOSUFFIXES(BUF_GETBUF_) |
800d4c59 | 378 | |
9b5ac6ff | 379 | /* --- @buf_putbuf{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 380 | * |
381 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 382 | * @buf *bb@ = buffer to write |
800d4c59 | 383 | * |
384 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
385 | * | |
9b5ac6ff | 386 | * Use: Puts the contents of a buffer to a buffer. |
800d4c59 | 387 | */ |
388 | ||
9b5ac6ff | 389 | #define BUF_PUTBUF_(n, W, w) \ |
390 | int buf_putbuf##w(buf *b, buf *bb) \ | |
391 | { return (buf_putmem##w(b, BBASE(bb), BLEN(bb))); } | |
392 | BUF_DOSUFFIXES(BUF_PUTBUF_) | |
800d4c59 | 393 | |
9b5ac6ff | 394 | /* --- @buf_putstr{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 395 | * |
396 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 397 | * @const char *p@ = string to write |
800d4c59 | 398 | * |
399 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
400 | * | |
9b5ac6ff | 401 | * Use: Puts a null-terminated string to a buffer. |
800d4c59 | 402 | */ |
403 | ||
9b5ac6ff | 404 | #define BUF_PUTSTR_(n, W, w) \ |
405 | int buf_putstr##w(buf *b, const char *p) \ | |
406 | { return (buf_putmem##w(b, p, strlen(p))); } | |
407 | BUF_DOSUFFIXES(BUF_PUTSTR_) | |
800d4c59 | 408 | |
409 | /*----- That's all, folks -------------------------------------------------*/ |