chiark / gitweb /
@@@ remote works?
[mLib] / struct / buf.c
CommitLineData
800d4c59 1/* -*-c-*-
800d4c59 2 *
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
49void 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 66void 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
81void 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
96void 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
111int 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
123void 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
139int 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
152int 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
185void *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
206int 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
224int 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
241int 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 }
267DOUINTCONV(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
279int 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
285int 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
291int 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 }
315DOUINTCONV(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
327int 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
333int 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
339int 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
356static 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 }
389DOUINTCONV(BUF_GETMEM_)
800d4c59 390
800d4c59 391void *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
399static 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
409void *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
417void *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
425void *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 }
458DOUINTCONV(BUF_PUTMEM_)
800d4c59 459
e63124bc
MW
460#ifndef HAVE_UINT64
461
462void *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
470void *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
478void *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 488int 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 522BUF_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))); }
537BUF_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))); }
552BUF_DOSUFFIXES(BUF_PUTSTR_)
800d4c59 553
554/*----- That's all, folks -------------------------------------------------*/