5 * (c) 2001 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software; you can redistribute it and/or modify
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.
17 * mLib is distributed in the hope that it will be useful,
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.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
36 /*----- Main code ---------------------------------------------------------*/
38 /* --- @buf_init@ --- *
40 * Arguments: @buf *b@ = pointer to a buffer block
41 * @void *p@ = pointer to a buffer
42 * @size_t sz@ = size of the buffer
46 * Use: Initializes the buffer block appropriately.
49 void buf_init(buf *b, void *p, size_t sz)
56 /* --- @dbuf_init@ --- *
58 * Arguments: @dbuf *db@ = pointer to a dynamic buffer block
62 * Use: Initializes a dynamic buffer. The buffer is initially empty,
63 * and ready for writing.
66 void dbuf_init(dbuf *db)
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;
72 /* --- @dbuf_reset@ --- *
74 * Arguments: @dbuf *db@ = pointer to a buffer block
78 * Use: Resets a buffer so that it can be written again.
81 void dbuf_reset(dbuf *db)
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;
87 /* --- @dbuf_destroy@ --- *
89 * Arguments: @dbuf *db@ = pointer to a buffer block
93 * Use: Release all of the resources held by a dynamic buffer.
96 void dbuf_destroy(dbuf *db)
98 if (db->_b.base) x_free(db->a, db->_b.base);
102 /* --- @buf_break@ --- *
104 * Arguments: @buf *b@ = pointer to a buffer block
106 * Returns: Some negative value.
108 * Use: Marks a buffer as broken.
111 int buf_break(buf *b) { b->f |= BF_BROKEN; return (-1); }
113 /* --- @buf_flip@ --- *
115 * Arguments: @buf *b@ = pointer to a buffer block
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.
123 void buf_flip(buf *b)
125 b->limit = b->p; b->p = b->base;
129 /* --- @buf_ensure@ --- *
131 * Arguments: @buf *b@ = pointer to a buffer block
132 * @size_t sz@ = size of data wanted
134 * Returns: Zero if it worked, nonzero if there wasn't enough space.
136 * Use: Ensures that there are @sz@ bytes still in the buffer.
139 int buf_ensure(buf *b, size_t sz) { return (BENSURE(b, sz)); }
141 /* --- @buf_tryextend@ --- *
143 * Arguments: @buf *b@ = pointer to a buffer block
144 * @size_t sz@ = size of data wanted
146 * Returns: Zero if it worked, nonzero if the buffer won't grow.
148 * Use: Extend the buffer so that at least @sz@ bytes are available.
149 * This only works if the buffer is allocated.
152 int buf_tryextend(buf *b, size_t sz)
157 if (~b->f&(BF_ALLOC | BF_WRITE))
158 { b->f |= BF_BROKEN; return (-1); }
160 len = BLEN(&db->_b); sz += len;
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;
170 db->_b.limit = db->_b.base + newsz;
174 /* --- @buf_get@ --- *
176 * Arguments: @buf *b@ = pointer to a buffer block
177 * @size_t sz@ = size of the buffer
179 * Returns: Pointer to the place in the buffer.
181 * Use: Reserves a space in the buffer of the requested size, and
182 * returns its start address.
185 void *buf_get(buf *b, size_t sz)
195 /* --- @buf_put@ --- *
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
201 * Returns: Zero if it worked, nonzero if there wasn't enough space.
203 * Use: Fetches data from some place and puts it in the buffer
206 int buf_put(buf *b, const void *p, size_t sz)
210 memcpy(BCUR(b), p, sz);
215 /* --- @buf_getbyte@ --- *
217 * Arguments: @buf *b@ = pointer to a buffer block
219 * Returns: A byte, or less than zero if there wasn't a byte there.
221 * Use: Gets a single byte from a buffer.
224 int buf_getbyte(buf *b)
231 /* --- @buf_putbyte@ --- *
233 * Arguments: @buf *b@ = pointer to a buffer block
234 * @int ch@ = byte to write
236 * Returns: Zero if OK, nonzero if there wasn't enough space.
238 * Use: Puts a single byte in a buffer.
241 int buf_putbyte(buf *b, int ch)
249 /* --- @buf_getu{8,{16,24,32,64}{,l,b}}@ --- *
251 * Arguments: @buf *b@ = pointer to a buffer block
252 * @uintSZ *w@ = where to put the word
254 * Returns: Zero if OK, or nonzero if there wasn't a word there.
256 * Use: Gets a word of appropriate size and order from a buffer.
259 #define BUF_GETU_(n, W, w) \
260 int buf_getu##w(buf *b, uint##n *ww) \
262 if (BENSURE(b, SZ_##W)) return (-1); \
263 *ww = LOAD##W(b->p); \
267 DOUINTCONV(BUF_GETU_)
269 /* --- @buf_getk64{,l,b}@ --- *
271 * Arguments: @buf *b@ = pointer to a buffer block
272 * @kludge64 *w@ = where to put the word
274 * Returns: Zero if OK, or nonzero if there wasn't a word there.
276 * Use: Gets a word of appropriate size and order from a buffer.
279 int buf_getk64(buf *b, kludge64 *w)
281 if (BENSURE(b, 8)) return (-1);
282 LOAD64_(*w, b->p); BSTEP(b, 8); return (0);
285 int buf_getk64l(buf *b, kludge64 *w)
287 if (BENSURE(b, 8)) return (-1);
288 LOAD64_L_(*w, b->p); BSTEP(b, 8); return (0);
291 int buf_getk64b(buf *b, kludge64 *w)
293 if (BENSURE(b, 8)) return (-1);
294 LOAD64_B_(*w, b->p); BSTEP(b, 8); return (0);
297 /* --- @buf_putu{8,{16,24,32,64}{,l,b}}@ --- *
299 * Arguments: @buf *b@ = pointer to a buffer block
300 * @uintSZ w@ = word to write
302 * Returns: Zero if OK, or nonzero if there wasn't enough space
304 * Use: Puts a word into a buffer with appropriate size and order.
307 #define BUF_PUTU_(n, W, w) \
308 int buf_putu##w(buf *b, uint##n ww) \
310 if (BENSURE(b, SZ_##W)) return (-1); \
311 STORE##W(b->p, ww); \
315 DOUINTCONV(BUF_PUTU_)
317 /* --- @buf_putk64{,l,b}@ --- *
319 * Arguments: @buf *b@ = pointer to a buffer block
320 * @kludge64 w@ = word to write
322 * Returns: Zero if OK, or nonzero if there wasn't enough space
324 * Use: Gets a word of appropriate size and order from a buffer.
327 int buf_putk64(buf *b, kludge64 w)
329 if (BENSURE(b, 8)) return (-1);
330 STORE64_(b->p, w); BSTEP(b, 8); return (0);
333 int buf_putk64l(buf *b, kludge64 w)
335 if (BENSURE(b, 8)) return (-1);
336 STORE64_L_(b->p, w); BSTEP(b, 8); return (0);
339 int buf_putk64b(buf *b, kludge64 w)
341 if (BENSURE(b, 8)) return (-1);
342 STORE64_B_(b->p, w); BSTEP(b, 8); return (0);
347 * Arguments: @buf *b@ = pointer to a buffer block
348 * @size_t *nn@ = where to put the length
350 * Returns: Zero if OK, nonzero if there wasn't a null byte to be found.
352 * Use: Finds a terminating null byte. The length includes this
356 static int findz(buf *b, size_t *nn)
360 if ((p = memchr(BCUR(b), 0, BLEFT(b))) == 0) {
364 *nn = p - BCUR(b) + 1;
368 /* --- @buf_getmem{8,{16,24,32,64}{,l,b},z} --- *
370 * Arguments: @buf *b@ = pointer to a buffer block
371 * @size_t *nn@ = where to put the length
373 * Returns: Pointer to the buffer data, or null.
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-
380 #define BUF_GETMEM_(n, W, w) \
381 void *buf_getmem##w(buf *b, size_t *nn) \
384 if (buf_getu##w(b, &sz)) return (0); \
385 if (BENSURE(b, sz)) return (0); \
387 return (buf_get(b, sz)); \
389 DOUINTCONV(BUF_GETMEM_)
391 void *buf_getmemz(buf *b, size_t *nn)
393 if (findz(b, nn)) return (0);
394 return (buf_get(b, *nn));
399 static void *getmem_k64(buf *b, size_t *nn_out, kludge64 k)
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));
409 void *buf_getmem64(buf *b, size_t *nn)
413 if (buf_getk64(b, &k)) return (-1);
414 return (getmem_k64(b, nn, k));
417 void *buf_getmem64b(buf *b, size_t *nn)
421 if (buf_getk64b(b, &k)) return (-1);
422 return (getmem_k64(b, nn, k));
425 void *buf_getmem64l(buf *b, size_t *nn)
429 if (buf_getk64l(b, &k)) return (-1);
430 return (getmem_k64(b, nn, k));
435 /* --- @buf_putmem{8,{16,24,32,64}{,l,b},z} --- *
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
441 * Returns: Zero if OK, nonzero if there wasn't enough space.
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-
448 #define BUF_PUTMEM_(n, W, w) \
449 int buf_putmem##w(buf *b, const void *p, size_t sz) \
451 MUFFLE_WARNINGS_STMT \
452 (CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \
453 { assert(sz <= MASK##W); }); \
454 if (buf_putu##w(b, sz) || buf_put(b, p, sz)) \
458 DOUINTCONV(BUF_PUTMEM_)
462 void *buf_putmem64(buf *b, const void *p, size_t n)
466 ASSIGN64(k, n); if (buf_putk64(b, k) || buf_put(b, p, n)) return (-1);
470 void *buf_putmem64b(buf *b, const void *p, size_t n)
474 ASSIGN64(k, n); if (buf_putk64b(b, k) || buf_put(b, p, n)) return (-1);
478 void *buf_putmem64l(buf *b, const void *p, size_t n)
482 ASSIGN64(k, n); if (buf_putk64l(b, k) || buf_put(b, p, n)) return (-1);
488 int buf_putmemz(buf *b, const void *p, size_t n)
492 assert(!memchr(p, 0, n));
493 if ((q = buf_get(b, n + 1)) == 0)
500 /* --- @buf_getbuf{8,{16,24,32,64}{,l,b},z} --- *
502 * Arguments: @buf *b@ = pointer to a buffer block
503 * @buf *bb@ = where to put the result
505 * Returns: Zero if it worked, nonzero if there wasn't enough space.
507 * Use: Gets a block of data from a buffer, and writes its bounds to
511 #define BUF_GETBUF_(n, W, w) \
512 int buf_getbuf##w(buf *b, buf *bb) \
517 if ((p = buf_getmem##w(b, &sz)) == 0) \
519 buf_init(bb, p, sz); \
522 BUF_DOSUFFIXES(BUF_GETBUF_)
524 /* --- @buf_putbuf{8,{16,24,32,64}{,l,b},z} --- *
526 * Arguments: @buf *b@ = pointer to a buffer block
527 * @buf *bb@ = buffer to write
529 * Returns: Zero if it worked, nonzero if there wasn't enough space.
531 * Use: Puts the contents of a buffer to a buffer.
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_)
539 /* --- @buf_putstr{8,{16,24,32,64}{,l,b},z} --- *
541 * Arguments: @buf *b@ = pointer to a buffer block
542 * @const char *p@ = string to write
544 * Returns: Zero if it worked, nonzero if there wasn't enough space.
546 * Use: Puts a null-terminated string to a buffer.
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_)
554 /*----- That's all, folks -------------------------------------------------*/