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 | ||
c91413e6 | 56 | /* --- @dbuf_create@ --- * |
e63124bc MW |
57 | * |
58 | * Arguments: @dbuf *db@ = pointer to a dynamic buffer block | |
59 | * | |
60 | * Returns: --- | |
61 | * | |
62 | * Use: Initializes a dynamic buffer. The buffer is initially empty, | |
63 | * and ready for writing. | |
64 | */ | |
65 | ||
c91413e6 | 66 | void dbuf_create(dbuf *db) |
e63124bc MW |
67 | { |
68 | db->_b.base = db->_b.p = db->_b.limit = 0; db->_b.f = BF_ALLOC | BF_WRITE; | |
69 | db->a = &arena_stdlib; db->sz = 0; | |
70 | } | |
71 | ||
72 | /* --- @dbuf_reset@ --- * | |
73 | * | |
74 | * Arguments: @dbuf *db@ = pointer to a buffer block | |
75 | * | |
76 | * Returns: --- | |
77 | * | |
78 | * Use: Resets a buffer so that it can be written again. | |
79 | */ | |
80 | ||
81 | void dbuf_reset(dbuf *db) | |
82 | { | |
83 | db->_b.p = db->_b.base; db->_b.limit = db->_b.base + db->sz; | |
84 | db->_b.f = (db->_b.f&~BF_BROKEN) | BF_WRITE; | |
85 | } | |
86 | ||
87 | /* --- @dbuf_destroy@ --- * | |
88 | * | |
89 | * Arguments: @dbuf *db@ = pointer to a buffer block | |
90 | * | |
91 | * Returns: --- | |
92 | * | |
93 | * Use: Release all of the resources held by a dynamic buffer. | |
94 | */ | |
95 | ||
96 | void dbuf_destroy(dbuf *db) | |
97 | { | |
98 | if (db->_b.base) x_free(db->a, db->_b.base); | |
c91413e6 | 99 | dbuf_create(db); |
e63124bc MW |
100 | } |
101 | ||
800d4c59 | 102 | /* --- @buf_break@ --- * |
103 | * | |
104 | * Arguments: @buf *b@ = pointer to a buffer block | |
105 | * | |
106 | * Returns: Some negative value. | |
107 | * | |
108 | * Use: Marks a buffer as broken. | |
109 | */ | |
110 | ||
111 | int buf_break(buf *b) { b->f |= BF_BROKEN; return (-1); } | |
112 | ||
113 | /* --- @buf_flip@ --- * | |
114 | * | |
115 | * Arguments: @buf *b@ = pointer to a buffer block | |
116 | * | |
117 | * Returns: --- | |
118 | * | |
119 | * Use: Flips a buffer so that if you've just been writing to it, | |
120 | * you can now read from the bit you've written. | |
121 | */ | |
122 | ||
123 | void buf_flip(buf *b) | |
124 | { | |
e63124bc MW |
125 | b->limit = b->p; b->p = b->base; |
126 | b->f &= ~BF_WRITE; | |
800d4c59 | 127 | } |
128 | ||
129 | /* --- @buf_ensure@ --- * | |
130 | * | |
131 | * Arguments: @buf *b@ = pointer to a buffer block | |
132 | * @size_t sz@ = size of data wanted | |
133 | * | |
134 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
135 | * | |
136 | * Use: Ensures that there are @sz@ bytes still in the buffer. | |
137 | */ | |
138 | ||
139 | int buf_ensure(buf *b, size_t sz) { return (BENSURE(b, sz)); } | |
140 | ||
e63124bc MW |
141 | /* --- @buf_tryextend@ --- * |
142 | * | |
143 | * Arguments: @buf *b@ = pointer to a buffer block | |
144 | * @size_t sz@ = size of data wanted | |
145 | * | |
146 | * Returns: Zero if it worked, nonzero if the buffer won't grow. | |
147 | * | |
148 | * Use: Extend the buffer so that at least @sz@ bytes are available. | |
149 | * This only works if the buffer is allocated. | |
150 | */ | |
151 | ||
152 | int buf_tryextend(buf *b, size_t sz) | |
153 | { | |
154 | dbuf *db; | |
155 | size_t newsz, len; | |
156 | ||
157 | if (~b->f&(BF_ALLOC | BF_WRITE)) | |
158 | { b->f |= BF_BROKEN; return (-1); } | |
159 | db = (dbuf *)b; | |
160 | len = BLEN(&db->_b); sz += len; | |
161 | if (db->sz >= sz) | |
162 | newsz = db->sz; | |
163 | else { | |
164 | newsz = db->sz ? 2*db->sz : 64; | |
165 | while (newsz < sz) { assert(newsz < ((size_t)-1)/2); newsz *= 2; } | |
166 | if (!db->_b.base) db->_b.base = x_alloc(db->a, newsz); | |
167 | else db->_b.base = x_realloc(db->a, db->_b.base, newsz, db->sz); | |
168 | db->_b.p = db->_b.base + len; db->sz = newsz; | |
169 | } | |
170 | db->_b.limit = db->_b.base + newsz; | |
171 | return (0); | |
172 | } | |
173 | ||
800d4c59 | 174 | /* --- @buf_get@ --- * |
175 | * | |
176 | * Arguments: @buf *b@ = pointer to a buffer block | |
177 | * @size_t sz@ = size of the buffer | |
178 | * | |
179 | * Returns: Pointer to the place in the buffer. | |
180 | * | |
181 | * Use: Reserves a space in the buffer of the requested size, and | |
182 | * returns its start address. | |
183 | */ | |
184 | ||
185 | void *buf_get(buf *b, size_t sz) | |
186 | { | |
187 | void *p; | |
188 | if (BENSURE(b, sz)) | |
189 | return (0); | |
190 | p = BCUR(b); | |
191 | BSTEP(b, sz); | |
192 | return (p); | |
193 | } | |
194 | ||
195 | /* --- @buf_put@ --- * | |
196 | * | |
197 | * Arguments: @buf *b@ = pointer to a buffer block | |
198 | * @const void *p@ = pointer to a buffer | |
199 | * @size_t sz@ = size of the buffer | |
200 | * | |
201 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
202 | * | |
203 | * Use: Fetches data from some place and puts it in the buffer | |
204 | */ | |
205 | ||
206 | int buf_put(buf *b, const void *p, size_t sz) | |
207 | { | |
208 | if (BENSURE(b, sz)) | |
209 | return (-1); | |
210 | memcpy(BCUR(b), p, sz); | |
211 | BSTEP(b, sz); | |
212 | return (0); | |
213 | } | |
214 | ||
215 | /* --- @buf_getbyte@ --- * | |
216 | * | |
217 | * Arguments: @buf *b@ = pointer to a buffer block | |
218 | * | |
219 | * Returns: A byte, or less than zero if there wasn't a byte there. | |
220 | * | |
221 | * Use: Gets a single byte from a buffer. | |
222 | */ | |
223 | ||
224 | int buf_getbyte(buf *b) | |
225 | { | |
226 | if (BENSURE(b, 1)) | |
227 | return (-1); | |
228 | return (*b->p++); | |
229 | } | |
230 | ||
231 | /* --- @buf_putbyte@ --- * | |
232 | * | |
233 | * Arguments: @buf *b@ = pointer to a buffer block | |
234 | * @int ch@ = byte to write | |
235 | * | |
236 | * Returns: Zero if OK, nonzero if there wasn't enough space. | |
237 | * | |
238 | * Use: Puts a single byte in a buffer. | |
239 | */ | |
240 | ||
241 | int buf_putbyte(buf *b, int ch) | |
242 | { | |
243 | if (BENSURE(b, 1)) | |
244 | return (-1); | |
245 | *b->p++ = ch; | |
246 | return (0); | |
247 | } | |
248 | ||
9b5ac6ff | 249 | /* --- @buf_getu{8,{16,24,32,64}{,l,b}}@ --- * |
800d4c59 | 250 | * |
251 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 252 | * @uintSZ *w@ = where to put the word |
800d4c59 | 253 | * |
254 | * Returns: Zero if OK, or nonzero if there wasn't a word there. | |
255 | * | |
9b5ac6ff | 256 | * Use: Gets a word of appropriate size and order from a buffer. |
800d4c59 | 257 | */ |
258 | ||
9b5ac6ff | 259 | #define BUF_GETU_(n, W, w) \ |
260 | int buf_getu##w(buf *b, uint##n *ww) \ | |
261 | { \ | |
262 | if (BENSURE(b, SZ_##W)) return (-1); \ | |
263 | *ww = LOAD##W(b->p); \ | |
264 | BSTEP(b, SZ_##W); \ | |
265 | return (0); \ | |
266 | } | |
267 | DOUINTCONV(BUF_GETU_) | |
800d4c59 | 268 | |
b64eb60f MW |
269 | /* --- @buf_getk64{,l,b}@ --- * |
270 | * | |
271 | * Arguments: @buf *b@ = pointer to a buffer block | |
272 | * @kludge64 *w@ = where to put the word | |
273 | * | |
274 | * Returns: Zero if OK, or nonzero if there wasn't a word there. | |
275 | * | |
276 | * Use: Gets a word of appropriate size and order from a buffer. | |
277 | */ | |
278 | ||
279 | int buf_getk64(buf *b, kludge64 *w) | |
280 | { | |
281 | if (BENSURE(b, 8)) return (-1); | |
282 | LOAD64_(*w, b->p); BSTEP(b, 8); return (0); | |
283 | } | |
284 | ||
285 | int buf_getk64l(buf *b, kludge64 *w) | |
286 | { | |
287 | if (BENSURE(b, 8)) return (-1); | |
288 | LOAD64_L_(*w, b->p); BSTEP(b, 8); return (0); | |
289 | } | |
290 | ||
291 | int buf_getk64b(buf *b, kludge64 *w) | |
292 | { | |
293 | if (BENSURE(b, 8)) return (-1); | |
294 | LOAD64_B_(*w, b->p); BSTEP(b, 8); return (0); | |
295 | } | |
296 | ||
9b5ac6ff | 297 | /* --- @buf_putu{8,{16,24,32,64}{,l,b}}@ --- * |
800d4c59 | 298 | * |
299 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 300 | * @uintSZ w@ = word to write |
800d4c59 | 301 | * |
9b5ac6ff | 302 | * Returns: Zero if OK, or nonzero if there wasn't enough space |
800d4c59 | 303 | * |
9b5ac6ff | 304 | * Use: Puts a word into a buffer with appropriate size and order. |
800d4c59 | 305 | */ |
306 | ||
9b5ac6ff | 307 | #define BUF_PUTU_(n, W, w) \ |
308 | int buf_putu##w(buf *b, uint##n ww) \ | |
309 | { \ | |
310 | if (BENSURE(b, SZ_##W)) return (-1); \ | |
311 | STORE##W(b->p, ww); \ | |
312 | BSTEP(b, SZ_##W); \ | |
313 | return (0); \ | |
314 | } | |
315 | DOUINTCONV(BUF_PUTU_) | |
800d4c59 | 316 | |
b64eb60f MW |
317 | /* --- @buf_putk64{,l,b}@ --- * |
318 | * | |
319 | * Arguments: @buf *b@ = pointer to a buffer block | |
320 | * @kludge64 w@ = word to write | |
321 | * | |
322 | * Returns: Zero if OK, or nonzero if there wasn't enough space | |
323 | * | |
324 | * Use: Gets a word of appropriate size and order from a buffer. | |
325 | */ | |
326 | ||
327 | int buf_putk64(buf *b, kludge64 w) | |
328 | { | |
329 | if (BENSURE(b, 8)) return (-1); | |
330 | STORE64_(b->p, w); BSTEP(b, 8); return (0); | |
331 | } | |
332 | ||
333 | int buf_putk64l(buf *b, kludge64 w) | |
334 | { | |
335 | if (BENSURE(b, 8)) return (-1); | |
336 | STORE64_L_(b->p, w); BSTEP(b, 8); return (0); | |
337 | } | |
338 | ||
339 | int buf_putk64b(buf *b, kludge64 w) | |
340 | { | |
341 | if (BENSURE(b, 8)) return (-1); | |
342 | STORE64_B_(b->p, w); BSTEP(b, 8); return (0); | |
343 | } | |
344 | ||
800d4c59 | 345 | /* --- @findz@ --- * |
346 | * | |
347 | * Arguments: @buf *b@ = pointer to a buffer block | |
348 | * @size_t *nn@ = where to put the length | |
349 | * | |
350 | * Returns: Zero if OK, nonzero if there wasn't a null byte to be found. | |
351 | * | |
95491579 MW |
352 | * Use: Finds a terminating null byte. The length includes this |
353 | * terminator. | |
800d4c59 | 354 | */ |
355 | ||
356 | static int findz(buf *b, size_t *nn) | |
357 | { | |
358 | octet *p; | |
359 | ||
a4589237 | 360 | if ((p = memchr(BCUR(b), 0, BLEFT(b))) == 0) { |
800d4c59 | 361 | buf_break(b); |
362 | return (-1); | |
363 | } | |
95491579 | 364 | *nn = p - BCUR(b) + 1; |
800d4c59 | 365 | return (0); |
366 | } | |
367 | ||
9b5ac6ff | 368 | /* --- @buf_getmem{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 369 | * |
370 | * Arguments: @buf *b@ = pointer to a buffer block | |
371 | * @size_t *nn@ = where to put the length | |
372 | * | |
373 | * Returns: Pointer to the buffer data, or null. | |
374 | * | |
9b5ac6ff | 375 | * Use: Gets a chunk of memory from a buffer. The suffix is the |
376 | * width and byte order of the length; @z@ means null- | |
377 | * terminated. | |
800d4c59 | 378 | */ |
379 | ||
9b5ac6ff | 380 | #define BUF_GETMEM_(n, W, w) \ |
381 | void *buf_getmem##w(buf *b, size_t *nn) \ | |
382 | { \ | |
383 | uint##n sz; \ | |
a4589237 | 384 | if (buf_getu##w(b, &sz)) return (0); \ |
f868c432 | 385 | if (BENSURE(b, sz)) return (0); \ |
9b5ac6ff | 386 | *nn = sz; \ |
387 | return (buf_get(b, sz)); \ | |
388 | } | |
389 | DOUINTCONV(BUF_GETMEM_) | |
800d4c59 | 390 | |
800d4c59 | 391 | void *buf_getmemz(buf *b, size_t *nn) |
392 | { | |
393 | if (findz(b, nn)) return (0); | |
394 | return (buf_get(b, *nn)); | |
395 | } | |
396 | ||
e63124bc MW |
397 | #ifndef HAVE_UINT64 |
398 | ||
399 | static void *getmem_k64(buf *b, size_t *nn_out, kludge64 k) | |
400 | { | |
401 | kludge64 szmax; | |
402 | size_t n; | |
403 | ||
404 | ASSIGN64(szmax, (size_t)-1); | |
405 | if (CMP64(k, >, szmax)) { buf_break(b); return (-1); } | |
406 | n = GET64(size_t, k); *nn_out = n; return (buf_get(b, n)); | |
407 | } | |
408 | ||
409 | void *buf_getmem64(buf *b, size_t *nn) | |
410 | { | |
411 | kludge64 k; | |
412 | ||
413 | if (buf_getk64(b, &k)) return (-1); | |
414 | return (getmem_k64(b, nn, k)); | |
415 | } | |
416 | ||
417 | void *buf_getmem64b(buf *b, size_t *nn) | |
418 | { | |
419 | kludge64 k; | |
420 | ||
421 | if (buf_getk64b(b, &k)) return (-1); | |
422 | return (getmem_k64(b, nn, k)); | |
423 | } | |
424 | ||
425 | void *buf_getmem64l(buf *b, size_t *nn) | |
426 | { | |
427 | kludge64 k; | |
428 | ||
429 | if (buf_getk64l(b, &k)) return (-1); | |
430 | return (getmem_k64(b, nn, k)); | |
431 | } | |
432 | ||
433 | #endif | |
434 | ||
9b5ac6ff | 435 | /* --- @buf_putmem{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 436 | * |
437 | * Arguments: @buf *b@ = pointer to a buffer block | |
438 | * @const void *p@ = pointer to data to write | |
439 | * @size_t n@ = length to write | |
440 | * | |
441 | * Returns: Zero if OK, nonzero if there wasn't enough space. | |
442 | * | |
9b5ac6ff | 443 | * Use: Writes a chunk of data to a buffer. The suffix is the |
444 | * width and byte order of the length; @z@ means null- | |
445 | * terminated. | |
800d4c59 | 446 | */ |
447 | ||
9b5ac6ff | 448 | #define BUF_PUTMEM_(n, W, w) \ |
449 | int buf_putmem##w(buf *b, const void *p, size_t sz) \ | |
450 | { \ | |
0d61a23c MW |
451 | MUFFLE_WARNINGS_STMT \ |
452 | (CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \ | |
453 | { assert(sz <= MASK##W); }); \ | |
a4589237 | 454 | if (buf_putu##w(b, sz) || buf_put(b, p, sz)) \ |
9b5ac6ff | 455 | return (-1); \ |
456 | return (0); \ | |
457 | } | |
458 | DOUINTCONV(BUF_PUTMEM_) | |
800d4c59 | 459 | |
e63124bc MW |
460 | #ifndef HAVE_UINT64 |
461 | ||
462 | void *buf_putmem64(buf *b, const void *p, size_t n) | |
463 | { | |
464 | kludge64 k; | |
465 | ||
466 | ASSIGN64(k, n); if (buf_putk64(b, k) || buf_put(b, p, n)) return (-1); | |
467 | return (0); | |
468 | } | |
469 | ||
470 | void *buf_putmem64b(buf *b, const void *p, size_t n) | |
471 | { | |
472 | kludge64 k; | |
473 | ||
474 | ASSIGN64(k, n); if (buf_putk64b(b, k) || buf_put(b, p, n)) return (-1); | |
475 | return (0); | |
476 | } | |
477 | ||
478 | void *buf_putmem64l(buf *b, const void *p, size_t n) | |
479 | { | |
480 | kludge64 k; | |
481 | ||
482 | ASSIGN64(k, n); if (buf_putk64l(b, k) || buf_put(b, p, n)) return (-1); | |
483 | return (0); | |
484 | } | |
485 | ||
486 | #endif | |
487 | ||
800d4c59 | 488 | int buf_putmemz(buf *b, const void *p, size_t n) |
489 | { | |
490 | octet *q; | |
491 | ||
492 | assert(!memchr(p, 0, n)); | |
493 | if ((q = buf_get(b, n + 1)) == 0) | |
494 | return (-1); | |
495 | memcpy(q, p, n); | |
496 | q[n] = 0; | |
497 | return (0); | |
498 | } | |
499 | ||
9b5ac6ff | 500 | /* --- @buf_getbuf{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 501 | * |
502 | * Arguments: @buf *b@ = pointer to a buffer block | |
503 | * @buf *bb@ = where to put the result | |
504 | * | |
505 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
506 | * | |
507 | * Use: Gets a block of data from a buffer, and writes its bounds to | |
9b5ac6ff | 508 | * another buffer. |
800d4c59 | 509 | */ |
510 | ||
9b5ac6ff | 511 | #define BUF_GETBUF_(n, W, w) \ |
512 | int buf_getbuf##w(buf *b, buf *bb) \ | |
513 | { \ | |
514 | void *p; \ | |
515 | size_t sz; \ | |
800d4c59 | 516 | \ |
9b5ac6ff | 517 | if ((p = buf_getmem##w(b, &sz)) == 0) \ |
518 | return (-1); \ | |
519 | buf_init(bb, p, sz); \ | |
520 | return (0); \ | |
800d4c59 | 521 | } |
9b5ac6ff | 522 | BUF_DOSUFFIXES(BUF_GETBUF_) |
800d4c59 | 523 | |
9b5ac6ff | 524 | /* --- @buf_putbuf{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 525 | * |
526 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 527 | * @buf *bb@ = buffer to write |
800d4c59 | 528 | * |
529 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
530 | * | |
9b5ac6ff | 531 | * Use: Puts the contents of a buffer to a buffer. |
800d4c59 | 532 | */ |
533 | ||
9b5ac6ff | 534 | #define BUF_PUTBUF_(n, W, w) \ |
535 | int buf_putbuf##w(buf *b, buf *bb) \ | |
536 | { return (buf_putmem##w(b, BBASE(bb), BLEN(bb))); } | |
537 | BUF_DOSUFFIXES(BUF_PUTBUF_) | |
800d4c59 | 538 | |
9b5ac6ff | 539 | /* --- @buf_putstr{8,{16,24,32,64}{,l,b},z} --- * |
800d4c59 | 540 | * |
541 | * Arguments: @buf *b@ = pointer to a buffer block | |
9b5ac6ff | 542 | * @const char *p@ = string to write |
800d4c59 | 543 | * |
544 | * Returns: Zero if it worked, nonzero if there wasn't enough space. | |
545 | * | |
9b5ac6ff | 546 | * Use: Puts a null-terminated string to a buffer. |
800d4c59 | 547 | */ |
548 | ||
9b5ac6ff | 549 | #define BUF_PUTSTR_(n, W, w) \ |
550 | int buf_putstr##w(buf *b, const char *p) \ | |
551 | { return (buf_putmem##w(b, p, strlen(p))); } | |
552 | BUF_DOSUFFIXES(BUF_PUTSTR_) | |
800d4c59 | 553 | |
554 | /*----- That's all, folks -------------------------------------------------*/ |