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 -------------------------------------------------*/