X-Git-Url: https://git.distorted.org.uk/~mdw/mLib/blobdiff_plain/c7da785d89746cbcdc25bdea0fd66156d4c61cb9..e63124bc579bfd97cfe2f620ddd84df9f20477d8:/struct/buf.h diff --git a/struct/buf.h b/struct/buf.h index 97dbd10..389d038 100644 --- a/struct/buf.h +++ b/struct/buf.h @@ -34,12 +34,17 @@ /*----- Header files ------------------------------------------------------*/ +#include #include #ifndef MLIB_BITS_H # include "bits.h" #endif +#ifndef MLIB_CONTROL_H +# include "control.h" +#endif + #ifndef MLIB_DSTR_H # include "dstr.h" #endif @@ -62,6 +67,19 @@ typedef struct buf { } buf; #define BF_BROKEN 1u /* Buffer is broken */ +#define BF_ALLOC 2u /* Buffer is dynamic */ +#define BF_WRITE 4u /* Currently writing to buffer */ + +typedef struct dbuf { + buf _b; + arena *a; /* Allocation arena */ + size_t sz; /* Allocated size */ +} dbuf; + +#define DBUF_INIT { { 0, 0, 0, BF_ALLOC | BF_WRITE}, &arena_stdlib, 0 } +#define DBUF_BUF(db) (&(db)->_b) + +extern const struct gprintf_ops buf_printops; /*----- Useful macros -----------------------------------------------------*/ @@ -78,13 +96,31 @@ typedef struct buf { #if GCC_VERSION_P(8, 0) # define BENSURE(b, sz) \ MUFFLE_WARNINGS_EXPR(GCC_WARNING("-Wint-in-bool-context"), \ - (BBAD(b) ? -1 : (sz) > BLEFT(b) ? (b)->f |= BF_BROKEN, -1 : 0)) + (BBAD(b) ? -1 : (sz) > BLEFT(b) ? buf_tryextend(b, sz) : 0)) #else # define BENSURE(b, sz) \ - (BBAD(b) ? -1 : (sz) > BLEFT(b) ? (b)->f |= BF_BROKEN, -1 : 0) + (BBAD(b) ? -1 : (sz) > BLEFT(b) ? buf_tryextend(b, sz) : 0) #endif -#define BUF_DOSUFFIXES(_) DOUINTCONV(_) _(z, z, z) +#define DBBASE(db) BBASE(DBUF_BUF(db)) +#define DBLIM(db) BLIM(DBUF_BUF(db)) +#define DBCUR(db) BCUR(DBUF_BUF(db)) +#define DBSZ(db) BSZ(DBUF_BUF(db)) +#define DBLEN(db) BLEN(DBUF_BUF(db)) +#define DBLEFT(db) BLEFT(DBUF_BUF(db)) +#define DBSTEP(db, sz) BSTEP(DBUF_BUF(db), (sz)) +#define DBBAD(db) BBAD(DBUF_BUF(db)) +#define DBOK(db) BOK(DBUF_BUF(db)) +#define DBENSURE(b, sz) BENSURE(DBUF_BUF(db), (sz)) + +#ifdef HAVE_UINT64 +# define BUF_DOKLUDGESUFFIXES(_) +#else +# define BUF_DOKLUDGESUFFIXES(_) \ + _(64, 64, 64) _(64, 64_B, 64b) _(64, 64_L, 64l) +#endif + +#define BUF_DOSUFFIXES(_) DOUINTCONV(_) BUF_DOKLUDGESUFFIXES(_) _(z, z, z) /*----- Functions provided ------------------------------------------------*/ @@ -101,6 +137,40 @@ typedef struct buf { extern void buf_init(buf */*b*/, void */*p*/, size_t /*sz*/); +/* --- @dbuf_init@ --- * + * + * Arguments: @dbuf *db@ = pointer to a dynamic buffer block + * + * Returns: --- + * + * Use: Initializes a dynamic buffer. The buffer is initially empty, + * and ready for writing. + */ + +extern void dbuf_init(dbuf */*db*/); + +/* --- @dbuf_reset@ --- * + * + * Arguments: @dbuf *db@ = pointer to a buffer block + * + * Returns: --- + * + * Use: Resets a buffer so that it can be written again. + */ + +extern void dbuf_reset(dbuf */*db*/); + +/* --- @dbuf_destroy@ --- * + * + * Arguments: @dbuf *db@ = pointer to a buffer block + * + * Returns: --- + * + * Use: Release all of the resources held by a dynamic buffer. + */ + +extern void dbuf_destroy(dbuf */*db*/); + /* --- @buf_break@ --- * * * Arguments: @buf *b@ = pointer to a buffer block @@ -136,6 +206,19 @@ extern void buf_flip(buf */*b*/); extern int buf_ensure(buf */*b*/, size_t /*sz*/); +/* --- @buf_tryextend@ --- * + * + * Arguments: @buf *b@ = pointer to a buffer block + * @size_t sz@ = size of data wanted + * + * Returns: Zero if it worked, nonzero if the buffer won't grow. + * + * Use: Extend the buffer so that at least @sz@ bytes are available. + * This only works if the buffer is allocated. + */ + +extern int buf_tryextend(buf */*b*/, size_t /*sz*/); + /* --- @buf_get@ --- * * * Arguments: @buf *b@ = pointer to a buffer block @@ -346,6 +429,146 @@ BUF_DOSUFFIXES(BUF_DECL_PUTDSTR_) extern int buf_putstr##w(buf */*b*/, const char */*p*/); BUF_DOSUFFIXES(BUF_DECL_PUTSTR_) +/* --- @buf_putf64{,b,l} --- * + * + * Arguments: @buf *b@ = a buffer to write to + * @double x@ = a number to write + * + * Returns: Zero on success, @-1@ on failure (and the buffer is broken). + * + * On C89, this function can't detect negative zero so these + * will be silently written as positive zero. + * + * This function doesn't distinguish NaNs. Any NaN is written + * as a quiet NaN with all payload bits zero. + * + * A finite value with too large a magnitude to be represented + * is rounded to the appropriate infinity. Other finite values + * are rounded as necessary, in the usual IEEE 754 round-to- + * nearest-or-even way. + */ + +extern int buf_putf64(buf */*b*/, double /*x*/); +extern int buf_putf64b(buf */*b*/, double /*x*/); +extern int buf_putf64l(buf */*b*/, double /*x*/); + +/* --- @buf_getf64{,b,l} --- * + * + * Arguments: @buf *b@ = a buffer to read from + * @double *x_out@ = where to put the result + * + * Returns: Zero on success, @-1@ on failure (and the buffer is broken). + * + * If the system supports NaNs, then any encoded NaN is returned + * as the value of @NAN@ in @@; otherwise, this function + * reports failure. + * + * In general, values are rounded to the nearest available + * value, in the way that the system usually rounds. If the + * system doesn't support infinities, then any encoded infinity + * is reported as the largest-possible-magnitude finite value + * instead. + */ + +extern int buf_getf64(buf */*b*/, double *x_/*out*/); +extern int buf_getf64b(buf */*b*/, double *x_/*out*/); +extern int buf_getf64l(buf */*b*/, double *x_/*out*/); + +#define BUF_ENCLOSETAG(tag, buf, mk, check, poke, lensz) \ + MC_BEFORE(tag##__save, \ + { (mk) = BLEN(buf); \ + if (!BENSURE(buf, lensz)) (buf)->p += (lensz); }) \ + MC_AFTER(tag##__poke, \ + { size_t _delta = BLEN(buf) - (mk) + (lensz); \ + assert(check); \ + if (BOK(buf)) poke((buf)->base + (mk), _delta); }) + +#define BUF_ENCLOSEZTAG(tag, buf) \ + MC_AFTER(tag##__zero, { buf_putbyte(buf, 0); }) + +#define BUF_ENCLOSENATIVETAG(tag, buf, mk, W) \ + BUF_ENCLOSETAG(tag, buf, mk, (_delta <= MASK##W), STORE##W, SZ_##W) + +#define BUF_STORESZK64(p, sz) \ + do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_((p), _k); } while (0) +#define BUF_STORESZK64_B(p, sz) \ + do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_B_((p), _k); } while (0) +#define BUF_STORESZK64_L(p, sz) \ + do { kludge64 _k; ASSIGN64(_k, (sz)); STORE64_L_((p), _k); } while (0) +#define BUF_ENCLOSEK64TAG(tag, buf, mk, W) \ + BUF_ENCLOSE(tag, buf, mk, 1, BUF_STORESZK##W, 8) + +#define BUF_ENCLOSE8(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 8) +#define BUF_ENCLOSE16(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16) +#define BUF_ENCLOSE16_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16_B) +#define BUF_ENCLOSE16_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 16_L) +#define BUF_ENCLOSE24(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24) +#define BUF_ENCLOSE24_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24_B) +#define BUF_ENCLOSE24_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 24_L) +#define BUF_ENCLOSE32(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32) +#define BUF_ENCLOSE32_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32_B) +#define BUF_ENCLOSE32_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 32_L) +#ifdef HAVE_UINT64 +# define BUF_ENCLOSE64(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64) +# define BUF_ENCLOSE64_B(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64_B) +# define BUF_ENCLOSE64_L(buf, mk) BUF_ENCLOSENATIVETAG(encl, buf, mk, 64_L) +#else +# define BUF_ENCLOSE64(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64) +# define BUF_ENCLOSE64_B(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64_B) +# define BUF_ENCLOSE64_L(buf, mk) BUF_ENCLOSEK64TAG(encl, buf, mk, 64_L) +#endif +#define BUF_ENCLOSEZ(buf) BUF_ENCLOSEZTAG(encl, buf) + +/* --- @buf_vputstrf@ --- * + * + * Arguments: @buf *b@ = pointer to a buffer + * @const char *p@ = pointer to @printf@-style format string + * @va_list *ap@ = argument handle + * + * Returns: The number of characters written to the string, or @-1@ on + * failure. + * + * Use: As for @buf_putstrf@, but may be used as a back-end to user- + * supplied functions with @printf@-style interfaces. + */ + +extern int buf_vputstrf(buf */*b*/, const char */*p*/, va_list */*ap*/); + +/* --- @buf_putstrf@ --- * + * + * Arguments: @buf *b@ = pointer to a buffer + * @const char *p@ = pointer to @printf@-style format string + * @...@ = argument handle + * + * Returns: The number of characters written to the string, or @-1@ on + * failure. + * + * Use: Format a string to a buffer. The resulting output is not + * null-terminated. + */ + +extern PRINTF_LIKE(2, 3) int buf_putstrf(buf */*b*/, const char */*p*/, ...); + +/* --- @buf_{,v}putstrf{8,{16,24,32,64}{,b,l},z}@ --- * + * + * Arguments: @buf *b@ = pointer to a buffer + * @const char *p@ = pointer to @printf@-style format string + * @va_list *ap@ = argument handle + * + * Returns: The number of characters written to the string, or @-1@ on + * failure. + * + * Use: As for @buf_putstr@, but using a format string. + */ + +#define BUF_DECL_PUTSTRF_(n, W, w) \ + extern int buf_vputstrf##w(buf */*b*/, \ + const char */*p*/, va_list */*ap*/); \ + extern PRINTF_LIKE(2, 3) \ + int buf_putstrf##w(buf */*b*/, const char */*p*/, ...); +BUF_DOSUFFIXES(BUF_DECL_PUTSTRF_) +#undef BUF_DECL_PUTSTRF_ + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus