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@ or @dbuf *db@ = 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_create@ --- *
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_create(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) { DBRESET(db); }
83 /* --- @dbuf_destroy@ --- *
85 * Arguments: @dbuf *db@ = pointer to a buffer block
89 * Use: Release all of the resources held by a dynamic buffer.
92 void dbuf_destroy(dbuf *db)
94 if (db->_b.base) x_free(db->a, db->_b.base);
98 /* --- @{,d}buf_break@ --- *
100 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
102 * Returns: Some negative value.
104 * Use: Marks a buffer as broken.
107 int buf_break(buf *b) { b->f |= BF_BROKEN; return (-1); }
108 int (dbuf_break)(dbuf *db) { return (dbuf_break(db)); }
110 /* --- @{,d}buf_flip@ --- *
112 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
116 * Use: Flips a buffer so that if you've just been writing to it,
117 * you can now read from the bit you've written.
120 void buf_flip(buf *b) { BFLIP(b); }
121 void (dbuf_flip)(dbuf *db) { dbuf_flip(db); }
123 /* --- @{,d}buf_ensure@ --- *
125 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
126 * @size_t sz@ = size of data wanted
128 * Returns: Zero if it worked, nonzero if there wasn't enough space.
130 * Use: Ensures that there are @sz@ bytes still in the buffer.
133 int buf_ensure(buf *b, size_t sz) { return (BENSURE(b, sz)); }
134 int (dbuf_ensure)(dbuf *db, size_t sz) { return (dbuf_ensure(db, sz)); }
136 /* --- @{,d}buf_tryextend@ --- *
138 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
139 * @size_t sz@ = size of data wanted
141 * Returns: Zero if it worked, nonzero if the buffer won't grow.
143 * Use: Extend the buffer so that at least @sz@ bytes are available.
144 * This only works if the buffer is allocated.
147 int buf_tryextend(buf *b, size_t sz)
152 if (~b->f&(BF_ALLOC | BF_WRITE))
153 { b->f |= BF_BROKEN; return (-1); }
155 len = BLEN(&db->_b); sz += len;
159 newsz = db->sz ? 2*db->sz : 64;
160 while (newsz < sz) { assert(newsz < ((size_t)-1)/2); newsz *= 2; }
161 if (!db->_b.base) db->_b.base = x_alloc(db->a, newsz);
162 else db->_b.base = x_realloc(db->a, db->_b.base, newsz, db->sz);
163 db->_b.p = db->_b.base + len; db->sz = newsz;
165 db->_b.limit = db->_b.base + newsz;
168 int (dbuf_tryextend)(dbuf *db, size_t sz)
169 { return (dbuf_tryextend(db, sz)); }
171 /* --- @{,d}buf_get@ --- *
173 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
174 * @size_t sz@ = size of the buffer
176 * Returns: Pointer to the place in the buffer.
178 * Use: Reserves a space in the buffer of the requested size, and
179 * returns its start address.
182 void *buf_get(buf *b, size_t sz)
191 void *(dbuf_get)(dbuf *db, size_t sz)
192 { return (dbuf_get(db, sz)); }
194 /* --- @{,d}buf_put@ --- *
196 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
197 * @const void *p@ = pointer to a buffer
198 * @size_t sz@ = size of the buffer
200 * Returns: Zero if it worked, nonzero if there wasn't enough space.
202 * Use: Fetches data from some place and puts it in the buffer
205 int buf_put(buf *b, const void *p, size_t sz)
209 memcpy(BCUR(b), p, sz);
213 int (dbuf_put)(dbuf *db, const void *p, size_t sz)
214 { return (dbuf_put(db, p, sz)); }
216 /* --- @{,d}buf_getbyte@ --- *
218 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
220 * Returns: A byte, or less than zero if there wasn't a byte there.
222 * Use: Gets a single byte from a buffer.
225 int buf_getbyte(buf *b)
231 int (dbuf_getbyte)(dbuf *db)
232 { return (dbuf_getbyte(db)); }
234 /* --- @{,d}buf_putbyte@ --- *
236 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
237 * @int ch@ = byte to write
239 * Returns: Zero if OK, nonzero if there wasn't enough space.
241 * Use: Puts a single byte in a buffer.
244 int buf_putbyte(buf *b, int ch)
251 int (dbuf_putbyte)(dbuf *db, int ch)
252 { return (dbuf_putbyte(db, ch)); }
254 /* --- @{,d}buf_getu{8,{16,24,32,64}{,l,b}}@ --- *
256 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
257 * @uintSZ *w@ = where to put the word
259 * Returns: Zero if OK, or nonzero if there wasn't a word there.
261 * Use: Gets a word of appropriate size and order from a buffer.
264 #define BUF_GETU_(n, W, w) \
265 int buf_getu##w(buf *b, uint##n *ww) \
267 if (BENSURE(b, SZ_##W)) return (-1); \
268 *ww = LOAD##W(b->p); \
272 int (dbuf_getu##w)(dbuf *db, uint##n *ww) \
273 { return (dbuf_getu##w(db, ww)); }
274 DOUINTCONV(BUF_GETU_)
276 /* --- @{,d}buf_getk64{,l,b}@ --- *
278 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
279 * @kludge64 *w@ = where to put the word
281 * Returns: Zero if OK, or nonzero if there wasn't a word there.
283 * Use: Gets a word of appropriate size and order from a buffer.
286 int buf_getk64(buf *b, kludge64 *w)
288 if (BENSURE(b, 8)) return (-1);
289 LOAD64_(*w, b->p); BSTEP(b, 8); return (0);
292 int buf_getk64l(buf *b, kludge64 *w)
294 if (BENSURE(b, 8)) return (-1);
295 LOAD64_L_(*w, b->p); BSTEP(b, 8); return (0);
298 int buf_getk64b(buf *b, kludge64 *w)
300 if (BENSURE(b, 8)) return (-1);
301 LOAD64_B_(*w, b->p); BSTEP(b, 8); return (0);
304 int (dbuf_getk64)(dbuf *db, kludge64 *w) { return (dbuf_getk64(db, w)); }
305 int (dbuf_getk64l)(dbuf *db, kludge64 *w) { return (dbuf_getk64l(db, w)); }
306 int (dbuf_getk64b)(dbuf *db, kludge64 *w) { return (dbuf_getk64b(db, w)); }
308 /* --- @{,d}buf_putu{8,{16,24,32,64}{,l,b}}@ --- *
310 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
311 * @uintSZ w@ = word to write
313 * Returns: Zero if OK, or nonzero if there wasn't enough space
315 * Use: Puts a word into a buffer with appropriate size and order.
318 #define BUF_PUTU_(n, W, w) \
319 int buf_putu##w(buf *b, uint##n ww) \
321 if (BENSURE(b, SZ_##W)) return (-1); \
322 STORE##W(b->p, ww); \
326 int (dbuf_putu##w)(dbuf *db, uint##n ww) \
327 { return (dbuf_putu##w(db, ww)); }
328 DOUINTCONV(BUF_PUTU_)
330 /* --- @{,d}buf_putk64{,l,b}@ --- *
332 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
333 * @kludge64 w@ = word to write
335 * Returns: Zero if OK, or nonzero if there wasn't enough space
337 * Use: Gets a word of appropriate size and order from a buffer.
340 int buf_putk64(buf *b, kludge64 w)
342 if (BENSURE(b, 8)) return (-1);
343 STORE64_(b->p, w); BSTEP(b, 8); return (0);
346 int buf_putk64l(buf *b, kludge64 w)
348 if (BENSURE(b, 8)) return (-1);
349 STORE64_L_(b->p, w); BSTEP(b, 8); return (0);
352 int buf_putk64b(buf *b, kludge64 w)
354 if (BENSURE(b, 8)) return (-1);
355 STORE64_B_(b->p, w); BSTEP(b, 8); return (0);
358 int (dbuf_putk64)(dbuf *db, kludge64 w) { return (dbuf_putk64(db, w)); }
359 int (dbuf_putk64l)(dbuf *db, kludge64 w) { return (dbuf_putk64l(db, w)); }
360 int (dbuf_putk64b)(dbuf *db, kludge64 w) { return (dbuf_putk64b(db, w)); }
364 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
365 * @size_t *nn@ = where to put the length
367 * Returns: Zero if OK, nonzero if there wasn't a null byte to be found.
369 * Use: Finds a terminating null byte. The length includes this
373 static int findz(buf *b, size_t *nn)
377 if ((p = memchr(BCUR(b), 0, BLEFT(b))) == 0) {
381 *nn = p - BCUR(b) + 1;
385 /* --- @{,d}buf_getmem{8,{16,24,32,64}{,l,b},z} --- *
387 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
388 * @size_t *nn@ = where to put the length
390 * Returns: Pointer to the buffer data, or null.
392 * Use: Gets a chunk of memory from a buffer. The suffix is the
393 * width and byte order of the length; @z@ means null-
397 #define BUF_GETMEM_(n, W, w) \
398 void *buf_getmem##w(buf *b, size_t *nn) \
401 if (buf_getu##w(b, &sz)) return (0); \
402 if (BENSURE(b, sz)) return (0); \
404 return (buf_get(b, sz)); \
406 void *(dbuf_getmem##w)(dbuf *db, size_t *nn) \
407 { return (dbuf_getmem##w(db, nn)); }
408 DOUINTCONV(BUF_GETMEM_)
410 void *buf_getmemz(buf *b, size_t *nn)
412 if (findz(b, nn)) return (0);
413 return (buf_get(b, *nn));
415 void *(dbuf_getmemz)(dbuf *db, size_t *nn)
416 { return (dbuf_getmemz(db, nn)); }
420 static void *getmem_k64(buf *b, size_t *nn_out, kludge64 k)
425 ASSIGN64(szmax, (size_t)-1);
426 if (CMP64(k, >, szmax)) { buf_break(b); return (-1); }
427 n = GET64(size_t, k); *nn_out = n; return (buf_get(b, n));
430 void *buf_getmem64(buf *b, size_t *nn)
434 if (buf_getk64(b, &k)) return (-1);
435 return (getmem_k64(b, nn, k));
438 void *buf_getmem64l(buf *b, size_t *nn)
442 if (buf_getk64l(b, &k)) return (-1);
443 return (getmem_k64(b, nn, k));
446 void *buf_getmem64b(buf *b, size_t *nn)
450 if (buf_getk64b(b, &k)) return (-1);
451 return (getmem_k64(b, nn, k));
454 void *(dbuf_getmem64)(dbuf *db, size_t *nn)
455 { return (dbuf_getmem64(db, nn)); }
456 void *(dbuf_getmem64l)(dbuf *db, size_t *nn)
457 { return (dbuf_getmem64l(db, nn)); }
458 void *(dbuf_getmem64b)(dbuf *db, size_t *nn)
459 { return (dbuf_getmem64b(db, nn)); }
463 /* --- @{,d}buf_putmem{8,{16,24,32,64}{,l,b},z} --- *
465 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
466 * @const void *p@ = pointer to data to write
467 * @size_t n@ = length to write
469 * Returns: Zero if OK, nonzero if there wasn't enough space.
471 * Use: Writes a chunk of data to a buffer. The suffix is the
472 * width and byte order of the length; @z@ means null-
476 #define BUF_PUTMEM_(n, W, w) \
477 int buf_putmem##w(buf *b, const void *p, size_t sz) \
479 MUFFLE_WARNINGS_STMT \
480 (CLANG_WARNING("-Wtautological-constant-out-of-range-compare"), \
481 { assert(sz <= MASK##W); }); \
482 if (buf_putu##w(b, sz) || buf_put(b, p, sz)) \
486 int (dbuf_putmem##w)(dbuf *db, const void *p, size_t sz) \
487 { return (dbuf_putmem##w(db, p, sz)); }
488 DOUINTCONV(BUF_PUTMEM_)
492 void *buf_putmem64(buf *b, const void *p, size_t n)
496 ASSIGN64(k, n); if (buf_putk64(b, k) || buf_put(b, p, n)) return (-1);
500 void *buf_putmem64l(buf *b, const void *p, size_t n)
504 ASSIGN64(k, n); if (buf_putk64l(b, k) || buf_put(b, p, n)) return (-1);
508 void *buf_putmem64b(buf *b, const void *p, size_t n)
512 ASSIGN64(k, n); if (buf_putk64b(b, k) || buf_put(b, p, n)) return (-1);
516 int (dbuf_putmem64)(dbuf *db, const void *p, size_t n)
517 { return (dbuf_putmem64(db, p, n)); }
518 int (dbuf_putmem64l)(dbuf *db, const void *p, size_t n)
519 { return (dbuf_putmem64l(db, p, n)); }
520 int (dbuf_putmem64b)(dbuf *db, const void *p, size_t n)
521 { return (dbuf_putmem64b(db, p, n)); }
525 int buf_putmemz(buf *b, const void *p, size_t n)
529 assert(!memchr(p, 0, n));
530 if ((q = buf_get(b, n + 1)) == 0)
536 int (dbuf_putmemz)(dbuf *db, const void *p, size_t n)
537 { return (dbuf_putmemz(db, p, n)); }
539 /* --- @{,d}buf_getbuf{8,{16,24,32,64}{,l,b},z} --- *
541 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
542 * @buf *bb@ = where to put the result
544 * Returns: Zero if it worked, nonzero if there wasn't enough space.
546 * Use: Gets a block of data from a buffer, and writes its bounds to
550 #define BUF_GETBUF_(n, W, w) \
551 int buf_getbuf##w(buf *b, buf *bb) \
556 if ((p = buf_getmem##w(b, &sz)) == 0) \
558 buf_init(bb, p, sz); \
561 int (dbuf_getbuf##w)(dbuf *db, buf *bb) \
562 { return (dbuf_getbuf##w(db, bb)); }
563 BUF_DOSUFFIXES(BUF_GETBUF_)
565 /* --- @{,d}buf_putbuf{8,{16,24,32,64}{,l,b},z} --- *
567 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
568 * @buf *bb@ = buffer to write
570 * Returns: Zero if it worked, nonzero if there wasn't enough space.
572 * Use: Puts the contents of a buffer to a buffer.
575 #define BUF_PUTBUF_(n, W, w) \
576 int buf_putbuf##w(buf *b, buf *bb) \
577 { return (buf_putmem##w(b, BBASE(bb), BLEN(bb))); } \
578 int (dbuf_putbuf##w)(dbuf *db, buf *bb) \
579 { return (dbuf_putbuf##w(db, bb)); }
580 BUF_DOSUFFIXES(BUF_PUTBUF_)
582 /* --- @{,d}buf_putstr{8,{16,24,32,64}{,l,b},z} --- *
584 * Arguments: @buf *b@ or @dbuf *db@ = pointer to a buffer block
585 * @const char *p@ = string to write
587 * Returns: Zero if it worked, nonzero if there wasn't enough space.
589 * Use: Puts a null-terminated string to a buffer.
592 #define BUF_PUTSTR_(n, W, w) \
593 int buf_putstr##w(buf *b, const char *p) \
594 { return (buf_putmem##w(b, p, strlen(p))); } \
595 int (dbuf_putstr##w)(dbuf *db, const char *p) \
596 { return (dbuf_putstr##w(db, p)); }
597 BUF_DOSUFFIXES(BUF_PUTSTR_)
599 /*----- That's all, folks -------------------------------------------------*/