@@@ man wip
[mLib] / struct / buf.3
index 10b52cf..3b3ef7c 100644 (file)
@@ -19,7 +19,9 @@
 ..
 .ie t .ds o \(bu
 .el .ds o o
+.
 .TH buf 3 "23 September 2005" "Straylight/Edgeware" "mLib utilities library"
+.
 .SH NAME
 buf \- reading and writing stuff in buffers
 .\" @BBASE
@@ -32,16 +34,64 @@ buf \- reading and writing stuff in buffers
 .\" @BBAD
 .\" @BOK
 .\" @BENSURE
+
+.\" @DBBASE
+.\" @DBLIM
+.\" @DBCUR
+.\" @DBSZ
+.\" @DBLEN
+.\" @DBLEFT
+.\" @DBSTEP
+.\" @DBBAD
+.\" @DBOK
+.\" @DBENSURE
 .
 .\" @buf_init
+.
+.\" @dbuf_create
+.\" @dbuf_reset
+.\" @dbuf_destroy
+.\" @DBCREATE
+.\" @DBRESET
+.\" @DBDESTROY
+.\" @DBUF_INIT
+.\" @DBUF_BUF
+.
 .\" @buf_break
 .\" @buf_flip
 .\" @buf_ensure
+.\" @buf_tryextend
 .\" @buf_get
 .\" @buf_put
+.\" @dbuf_break
+.\" @dbuf_flip
+.\" @dbuf_ensure
+.\" @dbuf_tryextend
+.\" @dbuf_get
+.\" @dbuf_put
 .
 .\" @buf_getbyte
 .\" @buf_putbyte
+.\" @dbuf_getbyte
+.\" @dbuf_putbyte
+.
+.\" @buf_getf64
+.\" @buf_getf64l
+.\" @buf_getf64b
+.\" @buf_putf64
+.\" @buf_putf64l
+.\" @buf_putf64b
+.\" @dbuf_getf64
+.\" @dbuf_getf64l
+.\" @dbuf_getf64b
+.\" @dbuf_putf64
+.\" @dbuf_putf64l
+.\" @dbuf_putf64b
+.
+.\" @buf_putstrf
+.\" @buf_vputstrf
+.\" @dbuf_putstrf
+.\" @dbuf_vputstrf
 .
 .\" @buf_getu8
 .\" @buf_getu16
@@ -53,6 +103,28 @@ buf \- reading and writing stuff in buffers
 .\" @buf_getu32
 .\" @buf_getu32b
 .\" @buf_getu32l
+.\" @buf_getu64
+.\" @buf_getu64b
+.\" @buf_getu64l
+.\" @buf_getk64
+.\" @buf_getk64b
+.\" @buf_getk64l
+.\" @dbuf_getu8
+.\" @dbuf_getu16
+.\" @dbuf_getu16b
+.\" @dbuf_getu16l
+.\" @dbuf_getu24
+.\" @dbuf_getu24b
+.\" @dbuf_getu24l
+.\" @dbuf_getu32
+.\" @dbuf_getu32b
+.\" @dbuf_getu32l
+.\" @dbuf_getu64
+.\" @dbuf_getu64b
+.\" @dbuf_getu64l
+.\" @dbuf_getk64
+.\" @dbuf_getk64b
+.\" @dbuf_getk64l
 .
 .\" @buf_putu8
 .\" @buf_putu16
@@ -64,6 +136,28 @@ buf \- reading and writing stuff in buffers
 .\" @buf_putu32
 .\" @buf_putu32b
 .\" @buf_putu32l
+.\" @buf_putu64
+.\" @buf_putu64b
+.\" @buf_putu64l
+.\" @buf_putk64
+.\" @buf_putk64b
+.\" @buf_putk64l
+.\" @dbuf_putu8
+.\" @dbuf_putu16
+.\" @dbuf_putu16b
+.\" @dbuf_putu16l
+.\" @dbuf_putu24
+.\" @dbuf_putu24b
+.\" @dbuf_putu24l
+.\" @dbuf_putu32
+.\" @dbuf_putu32b
+.\" @dbuf_putu32l
+.\" @dbuf_putu64
+.\" @dbuf_putu64b
+.\" @dbuf_putu64l
+.\" @dbuf_putk64
+.\" @dbuf_putk64b
+.\" @dbuf_putk64l
 .
 .\" @buf_getbuf8
 .\" @buf_getbuf16
@@ -75,7 +169,24 @@ buf \- reading and writing stuff in buffers
 .\" @buf_getbuf32
 .\" @buf_getbuf32b
 .\" @buf_getbuf32l
+.\" @buf_getbuf64
+.\" @buf_getbuf64b
+.\" @buf_getbuf64l
 .\" @buf_getbufz
+.\" @dbuf_getbuf8
+.\" @dbuf_getbuf16
+.\" @dbuf_getbuf16b
+.\" @dbuf_getbuf16l
+.\" @dbuf_getbuf24
+.\" @dbuf_getbuf24b
+.\" @dbuf_getbuf24l
+.\" @dbuf_getbuf32
+.\" @dbuf_getbuf32b
+.\" @dbuf_getbuf32l
+.\" @dbuf_getbuf64
+.\" @dbuf_getbuf64b
+.\" @dbuf_getbuf64l
+.\" @dbuf_getbufz
 .
 .\" @buf_putbuf8
 .\" @buf_putbuf16
@@ -87,8 +198,26 @@ buf \- reading and writing stuff in buffers
 .\" @buf_putbuf32
 .\" @buf_putbuf32b
 .\" @buf_putbuf32l
+.\" @buf_putbuf64
+.\" @buf_putbuf64b
+.\" @buf_putbuf64l
 .\" @buf_putbufz
+.\" @dbuf_putbuf8
+.\" @dbuf_putbuf16
+.\" @dbuf_putbuf16b
+.\" @dbuf_putbuf16l
+.\" @dbuf_putbuf24
+.\" @dbuf_putbuf24b
+.\" @dbuf_putbuf24l
+.\" @dbuf_putbuf32
+.\" @dbuf_putbuf32b
+.\" @dbuf_putbuf32l
+.\" @dbuf_putbuf64
+.\" @dbuf_putbuf64b
+.\" @dbuf_putbuf64l
+.\" @dbuf_putbufz
 .
+.\" @buf_getmem8
 .\" @buf_getmem16
 .\" @buf_getmem16b
 .\" @buf_getmem16l
@@ -98,8 +227,24 @@ buf \- reading and writing stuff in buffers
 .\" @buf_getmem32
 .\" @buf_getmem32b
 .\" @buf_getmem32l
-.\" @buf_getmem8
+.\" @buf_getmem64
+.\" @buf_getmem64b
+.\" @buf_getmem64l
 .\" @buf_getmemz
+.\" @dbuf_getmem8
+.\" @dbuf_getmem16
+.\" @dbuf_getmem16b
+.\" @dbuf_getmem16l
+.\" @dbuf_getmem24
+.\" @dbuf_getmem24b
+.\" @dbuf_getmem24l
+.\" @dbuf_getmem32
+.\" @dbuf_getmem32b
+.\" @dbuf_getmem32l
+.\" @dbuf_getmem64
+.\" @dbuf_getmem64b
+.\" @dbuf_getmem64l
+.\" @dbuf_getmemz
 .
 .\" @buf_putmem8
 .\" @buf_putmem16
@@ -111,7 +256,24 @@ buf \- reading and writing stuff in buffers
 .\" @buf_putmem32
 .\" @buf_putmem32b
 .\" @buf_putmem32l
+.\" @buf_putmem64
+.\" @buf_putmem64b
+.\" @buf_putmem64l
 .\" @buf_putmemz
+.\" @dbuf_putmem8
+.\" @dbuf_putmem16
+.\" @dbuf_putmem16b
+.\" @dbuf_putmem16l
+.\" @dbuf_putmem24
+.\" @dbuf_putmem24b
+.\" @dbuf_putmem24l
+.\" @dbuf_putmem32
+.\" @dbuf_putmem32b
+.\" @dbuf_putmem32l
+.\" @dbuf_putmem64
+.\" @dbuf_putmem64b
+.\" @dbuf_putmem64l
+.\" @dbuf_putmemz
 .
 .\" @buf_putstr8
 .\" @buf_putstr16
@@ -123,7 +285,24 @@ buf \- reading and writing stuff in buffers
 .\" @buf_putstr32
 .\" @buf_putstr32b
 .\" @buf_putstr32l
+.\" @buf_putstr64
+.\" @buf_putstr64b
+.\" @buf_putstr64l
 .\" @buf_putstrz
+.\" @dbuf_putstr8
+.\" @dbuf_putstr16
+.\" @dbuf_putstr16b
+.\" @dbuf_putstr16l
+.\" @dbuf_putstr24
+.\" @dbuf_putstr24b
+.\" @dbuf_putstr24l
+.\" @dbuf_putstr32
+.\" @dbuf_putstr32b
+.\" @dbuf_putstr32l
+.\" @dbuf_putstr64
+.\" @dbuf_putstr64b
+.\" @dbuf_putstr64l
+.\" @dbuf_putstrz
 .
 .\" @buf_getdstr8
 .\" @buf_getdstr16
@@ -135,7 +314,24 @@ buf \- reading and writing stuff in buffers
 .\" @buf_getdstr32
 .\" @buf_getdstr32b
 .\" @buf_getdstr32l
+.\" @buf_getdstr64
+.\" @buf_getdstr64b
+.\" @buf_getdstr64l
 .\" @buf_getdstrz
+.\" @dbuf_getdstr8
+.\" @dbuf_getdstr16
+.\" @dbuf_getdstr16b
+.\" @dbuf_getdstr16l
+.\" @dbuf_getdstr24
+.\" @dbuf_getdstr24b
+.\" @dbuf_getdstr24l
+.\" @dbuf_getdstr32
+.\" @dbuf_getdstr32b
+.\" @dbuf_getdstr32l
+.\" @dbuf_getdstr64
+.\" @dbuf_getdstr64b
+.\" @dbuf_getdstr64l
+.\" @dbuf_getdstrz
 .
 .\" @buf_putdstr8
 .\" @buf_putdstr16
@@ -147,14 +343,154 @@ buf \- reading and writing stuff in buffers
 .\" @buf_putdstr32
 .\" @buf_putdstr32b
 .\" @buf_putdstr32l
+.\" @buf_putdstr64
+.\" @buf_putdstr64b
+.\" @buf_putdstr64l
 .\" @buf_putdstrz
+.\" @dbuf_putdstr8
+.\" @dbuf_putdstr16
+.\" @dbuf_putdstr16b
+.\" @dbuf_putdstr16l
+.\" @dbuf_putdstr24
+.\" @dbuf_putdstr24b
+.\" @dbuf_putdstr24l
+.\" @dbuf_putdstr32
+.\" @dbuf_putdstr32b
+.\" @dbuf_putdstr32l
+.\" @dbuf_putdstr64
+.\" @dbuf_putdstr64b
+.\" @dbuf_putdstr64l
+.\" @dbuf_putdstrz
+.
+.\" @buf_putstrf8
+.\" @buf_putstrf16
+.\" @buf_putstrf16b
+.\" @buf_putstrf16l
+.\" @buf_putstrf24
+.\" @buf_putstrf24b
+.\" @buf_putstrf24l
+.\" @buf_putstrf32
+.\" @buf_putstrf32b
+.\" @buf_putstrf32l
+.\" @buf_putstrf64
+.\" @buf_putstrf64b
+.\" @buf_putstrf64l
+.\" @buf_putstrfz
+.\" @buf_vputstrf8
+.\" @buf_vputstrf16
+.\" @buf_vputstrf16b
+.\" @buf_vputstrf16l
+.\" @buf_vputstrf24
+.\" @buf_vputstrf24b
+.\" @buf_vputstrf24l
+.\" @buf_vputstrf32
+.\" @buf_vputstrf32b
+.\" @buf_vputstrf32l
+.\" @buf_vputstrf64
+.\" @buf_vputstrf64b
+.\" @buf_vputstrf64l
+.\" @buf_vputstrfz
+.\" @dbuf_putstrf8
+.\" @dbuf_putstrf16
+.\" @dbuf_putstrf16b
+.\" @dbuf_putstrf16l
+.\" @dbuf_putstrf24
+.\" @dbuf_putstrf24b
+.\" @dbuf_putstrf24l
+.\" @dbuf_putstrf32
+.\" @dbuf_putstrf32b
+.\" @dbuf_putstrf32l
+.\" @dbuf_putstrf64
+.\" @dbuf_putstrf64b
+.\" @dbuf_putstrf64l
+.\" @dbuf_putstrfz
+.\" @dbuf_vputstrf8
+.\" @dbuf_vputstrf16
+.\" @dbuf_vputstrf16b
+.\" @dbuf_vputstrf16l
+.\" @dbuf_vputstrf24
+.\" @dbuf_vputstrf24b
+.\" @dbuf_vputstrf24l
+.\" @dbuf_vputstrf32
+.\" @dbuf_vputstrf32b
+.\" @dbuf_vputstrf32l
+.\" @dbuf_vputstrf64
+.\" @dbuf_vputstrf64b
+.\" @dbuf_vputstrf64l
+.\" @dbuf_vputstrfz
+.
+.\" @BUF_ENCLOSETAG
+.\" @BUF_ENCLOSEITAG
+.\" @BUF_ENCLOSEKTAG
+.\" @BUF_ENCLOSEZTAG
+.\" @BUF_ENCLOSE8
+.\" @BUF_ENCLOSE16
+.\" @BUF_ENCLOSE16_L
+.\" @BUF_ENCLOSE16_B
+.\" @BUF_ENCLOSE24
+.\" @BUF_ENCLOSE24_L
+.\" @BUF_ENCLOSE24_B
+.\" @BUF_ENCLOSE32
+.\" @BUF_ENCLOSE32_L
+.\" @BUF_ENCLOSE32_B
+.\" @BUF_ENCLOSE64
+.\" @BUF_ENCLOSE64_L
+.\" @BUF_ENCLOSE64_B
+.\" @BUF_ENCLOSEZ
+.\" @DBUF_ENCLOSETAG
+.\" @DBUF_ENCLOSEITAG
+.\" @DBUF_ENCLOSEKTAG
+.\" @DBUF_ENCLOSEZTAG
+.\" @DBUF_ENCLOSE8
+.\" @DBUF_ENCLOSE16
+.\" @DBUF_ENCLOSE16_L
+.\" @DBUF_ENCLOSE16_B
+.\" @DBUF_ENCLOSE24
+.\" @DBUF_ENCLOSE24_L
+.\" @DBUF_ENCLOSE24_B
+.\" @DBUF_ENCLOSE32
+.\" @DBUF_ENCLOSE32_L
+.\" @DBUF_ENCLOSE32_B
+.\" @DBUF_ENCLOSE64
+.\" @DBUF_ENCLOSE64_L
+.\" @DBUF_ENCLOSE64_B
+.\" @DBUF_ENCLOSEZ
+.
 .SH SYNOPSIS
 .nf
 .B "#include <mLib/dstr.h>"
 
 .B "typedef struct { ...\& } buf;"
+.B "typedef struct { ...\& } dbuf;"
 
 .BI "void buf_init(buf *" b ", void *" p ", size_t " sz );
+.BI "void dbuf_create(dbuf *" db );
+.BI "void dbuf_reset(dbuf *" db );
+.BI "void dbuf_destroy(dbuf *" db );
+.BI "buf *DBUF_BUF(dbuf *" db );
+.BI "void DBCREATE(dbuf *" db );
+.BI "void DBRESET(dbuf *" db );
+.BI "void DBDESTROY(dbuf *" db );
+.B "#define DBUF_INIT ..."
+
+.fi
+All of the following functions and macros exist in two variants:
+one with a name beginning
+.BR buf_ ,
+.BR B ,
+or
+.BR BUF_ ,
+and taking a first argument of type
+.BR "buf *" ;
+and a corresponding similarly named version with name beginning instead
+.BR dbuf_ ,
+.BR DB ,
+or
+.BR DBUF_ ,
+and taking a first argument of type
+.BR "dbuf *" .
+.nf
+
 .BI "void buf_flip(buf *" b );
 .BI "octet *BBASE(buf *" b );
 .BI "octet *BLIM(buf *" b );
@@ -162,12 +498,15 @@ buf \- reading and writing stuff in buffers
 .BI "ptrdiff_t BSZ(buf *" b );
 .BI "ptrdiff_t BLEN(buf *" b );
 .BI "ptrdiff_t BLEFT(buf *" b );
+.BI "void BFLIP(buf *" b );
 
 .BI "int buf_break(buf *" b );
+.BI "int BBREAK(buf *" b );
 .BI "int BBAD(buf *" b );
 .BI "int BOK(buf *" b );
 
 .BI "int buf_ensure(buf *" b ", size_t " sz );
+.BI "int buf_tryextend(buf *" b ", size_t " sz );
 .BI "int BENSURE(buf *" b ", size_t " sz );
 .BI "octet *BSTEP(buf *" b ", size_t " sz );
 
@@ -175,23 +514,144 @@ buf \- reading and writing stuff in buffers
 .BI "void *buf_put(buf *" b ", const void *" p ", size_t " sz );
 
 .BI "int buf_getbyte(buf *" b );
-.BI "int buf_putbyte(buf *" b ", int ch" );
-.BI "int buf_getu" suff "(buf *" b ", uint" suff " *" w );
+.BI "int buf_putbyte(buf *" b ", int " ch );
+
+.BI "int buf_putstr(buf *" b ", const char *" p ", ...);"
+.BI "int buf_vputstr(buf *" b ", const char *" p ", va_list *" ap );
+
+.fi
+For
+.I suff
+in
+.BR 8 ,
+.BR 16 ,
+.BR 16l ,
+.BR 16b ,
+.BR 24 ,
+.BR 24l ,
+.BR 24b ,
+.BR 32 ,
+.BR 32l ,
+and
+.BR 32b ,
+and, if a 64-bit integer type is available,
+.BR 64 ,
+.BR 64l ,
+and
+.BR 64b :
+.nf
 .BI "int buf_putu" suff "(buf *" b ", uint" suff " " w );
-.BI "void *buf_getmem" suff "(buf *" b ", size_t *" sz );
-.BI "int buf_putmem" suff "(buf *" b ", const void *" p ", size_t " sz );
-.BI "int buf_getbuf" suff "(buf *" b ", buf *" bb );
-.BI "int buf_putbuf" suff "(buf *" b ", buf *" bb );
-.BI "int buf_getdstr" suff "(buf *" b ", dstr *" d );
-.BI "int buf_putdstr" suff "(buf *" b ", dstr *" d );
+.BI "int buf_getu" suff "(buf *" b ", uint" suff " *" w );
+
+.fi
+For
+.I suff
+in
+.BR 64 ,
+.BR 64l ,
+and
+.BR 64b :
+.nf
+.BI "int buf_putk" suff "(buf *" b ", kludge64 " w );
+.BI "int buf_getk" suff "(buf *" b ", kludge64 *" w );
+
+.ta 2n
+.BI "BUF_ENCLOSETAG(" tag ", buf *" b ", size_t " mk ", " check ", " poke ", size_t " lensz )
+.I "   body"
+.BI "BUF_ENCLOSEITAG(" tag ", buf *" b ", size_t " mk ", " W )
+.I "   body"
+.BI "BUF_ENCLOSEKTAG(" tag ", buf *" b ", size_t " mk ", " W )
+.I "   body"
+.BI "BUF_ENCLOSEZTAG(" tag ", buf *" b )
+.I "   body"
+
+.fi
+For
+.I suff
+in
+.BR 8 ,
+.BR 16 ,
+.BR 16_L ,
+.BR 16_B ,
+.BR 24 ,
+.BR 24_L ,
+.BR 24_B ,
+.BR 32 ,
+.BR 32_L ,
+.BR 32_B ,
+.BR 64 ,
+.BR 64_L ,
+and
+.BR 64_B ,
+.nf
+.ta 2n
+.BI "BUF_ENCLOSE" suff "(buf *" b ", size_t " mk )
+.I "   body"
+
+.BI "BUF_ENCLOSEZ(buf *" b )
+.I "   body"
+
+.fi
+For
+.I suff
+in
+.BR 8 ,
+.BR 16 ,
+.BR 16l ,
+.BR 16b ,
+.BR 24 ,
+.BR 24l ,
+.BR 24b ,
+.BR 32 ,
+.BR 32l ,
+.BR 32b ,
+.BR 64 ,
+.BR 64l ,
+.BR 64b ,
+and
+.BR z :
+.nf
 .BI "int buf_putstr" suff "(buf *" b ", const char *" p );
+.BI "int dbuf_putstr" suff "(dbuf *" db ", const char *" p );
+.BI "int buf_putstr" suff "(buf *" b ", const char *" p ", ...);"
+.BI "int dbuf_putstr" suff "(dbuf *" db ", const char *" p ", ...);"
+.BI "int buf_vputstr" suff "(buf *" b ", const char *" p ", va_list *" ap );
+.BI "int dbuf_vputstr" suff "(dbuf *" db ", const char *" p ", va_list *" ap );
+.BI "int buf_putdstr" suff "(buf *" b ", dstr *" d );
+.BI "int dbuf_putdstr" suff "(dbuf *" db ", dstr *" d );
+.BI "int buf_getdstr" suff "(buf *" b ", dstr *" d );
+.BI "int dbuf_getdstr" suff "(dbuf *" db ", dstr *" d );
+.BI "int buf_putbuf" suff "(buf *" b ", buf *" bb );
+.BI "int dbuf_putbuf" suff "(dbuf *" db ", buf *" bb );
+.BI "int buf_getbuf" suff "(buf *" b ", buf *" bb );
+.BI "int dbuf_getbuf" suff "(dbuf *" db ", buf *" bb );
+.BI "int buf_putmem" suff "(buf *" b ", const void *" p ", size_t " sz );
+.BI "int dbuf_putmem" suff "(dbuf *" db ", const void *" p ", size_t " sz );
+.BI "void *buf_getmem" suff "(buf *" b ", size_t *" sz );
+.BI "void d*buf_getmem" suff "(dbuf *" db ", size_t *" sz );
+
 .fi
+For
+.I suff
+in
+.BR 64 ,
+.BR 64l ,
+and
+.BR 64b :
+.nf
+.BI "int buf_putf" suff "(buf *" b ", double " x );
+.BI "int dbuf_putf" suff "(dbuf *" db ", double " x );
+.BI "int buf_getf" suff "(buf *" b ", double *" x );
+.BI "int dbuf_getf" suff "(dbuf *" db ", double *" x );
+.fi
+.
 .SH DESCRIPTION
 The
 .B buf
 interface allows relatively convenient reading and writing of structured
 binary data from and to fixed-size memory buffers.  It's useful for
 formatting and parsing down network data packets, for example.
+.
 .SS "Buffer basics"
 A buffer has three important pointers associated with it:
 .TP
@@ -267,6 +727,10 @@ and to set
 .I current
 to
 .IR base .
+There is a macro version,
+.BR BFLIP ,
+which does the same thing,
+but it may evaluate its buffer argument multiple times.
 .PP
 A buffer can be
 .IR broken ,
@@ -279,12 +743,19 @@ call and just check the brokenness state at the end of their run.
 .PP
 The function
 .B buf_break
-will break a buffer.  The macro
+or its
+macro equivalent
+.B BBREAK
+will break a buffer:
+the function returns \-1 as a possible, but minor, convenience;
+the macro expands to a statement and cannot return a value.
+The macro
 .B BBAD
 reports true (nonzero) if its buffer argument is broken, or false (zero)
 otherwise; its counterpart
 .B BOK
 reports true if the buffer is OK, and false if it is broken.
+.
 .SS "Low-level buffer access"
 Access to the data in the buffer is usually sequential.  The
 .B BENSURE
@@ -329,6 +800,7 @@ function writes
 bytes of data starting at
 .I p
 to the buffer.  If it succeeded, it returns 0; otherwise it returns \-1.
+.
 .SS "Formatted buffer access"
 The function
 .B buf_getbyte
@@ -360,8 +832,65 @@ given, and returns zero; on failure, it returns \-1.  The function
 .BI buf_putu suff
 write an integer.  It returns zero on success or \-1 on failure.
 .PP
+For (portability to) platforms without 64-bit integers, the functions
+.B buf_getk64
+and
+.B buf_putk64
+(and
+.RB ` l '-
+and
+.RB ` b '-suffixed
+variants) perform the necessary functionality, but acting on the
+.B kludge64
+type; see
+.BR bits (3).
+.PP
+The functions
+.BR buf_getf64 ,
+.BR buf_getf64l ,
+and
+.BR buf_getf64b
+read 64-bit floating-point values
+in IEEE\ 754 Binary64 format
+from the buffer;
+as usual, the suffix indicates the byte ordering convention.
+On success, they store the result in
+.BI *x
+and return zero;
+on failure, they break the buffer and return zero.
+The functions
+.BR buf_putf64 ,
+.BR buf_putf64l ,
+and
+.BR buf_putf64b
+write floating-point numbers
+in IEEE\ 754 Binary64 format
+from the buffer.
+On success, they return zero; on failure, they return \-1.
+Note that these functions use IEEE\ 754 format
+even if this is not the platform-native floating-point representation.
+.PP
+The function
+.B buf_putstrf
+processes a
+.BR printf (3)-like
+format string and arguments,
+writing the output to the buffer.
+The function
+.B buf_vputstrf
+does the same,
+except that it reads arguments from a
+.B va_list
+captured argument tail,
+leaving the tail ready to read the next unprocessed argument.
+Both functions return the number of bytes written on success
+or \-1 on failure.
+Note that these functions apply no length framing or termination.
+.PP
 Functions which deal with block lengths assume the length is prefixed to
-the data, and don't include themselves.  They also have an additional
+the data, and don't include themselves.  They come in all of the integer
+size variants, including 64-bits even on platforms without 64-bit integers;
+they also have an additional
 .RB ` z '
 variant, which deals with zero-terminated data.  No checks are done on
 writing that the data written contains no zero bytes.
@@ -401,8 +930,242 @@ function
 .BI buf_putstr suff
 writes a standard C null-terminated string to a buffer.  All these
 functions return zero on success or \-1 on failure.
+.PP
+The function
+.BI buf_putstrf suff
+processes a
+.BR printf (3)-like
+format string and arguments,
+writing the output to the buffer.
+The function
+.BI buf_vputstrf suff
+does the same,
+except that it reads arguments from a
+.B va_list
+captured argument tail,
+leaving the tail ready to read the next unprocessed argument.
+Both functions return the number of bytes written on success
+or \-1 on failure.
+These functions add framing around the output:
+either a length prefix, or a trailing zero byte.
+.PP
+The
+.BI BUF_ENCLOSE suff
+macros are syntactically statement heads.
+(Notice that these macros use
+.RB ` _L '
+and
+.RB ` _B '
+suffixes for little- and big-endian byte order.)
+They leave space in the buffer for appropriate length framing,
+and execute the following
+.I body
+statement
+(which, of course, can be a compound statement enclosed in braces).
+When the
+.I body
+completes, the macro fills in space
+with the length of material written by the
+.IR body .
+The
+.I mk
+argument should be a variable of type
+.B size_t
+which will be overwritten by the macro.
+If the material is so large that its won't fit in the space
+then the buffer is broken.
+The
+.B BUF_ENCLOSEZ
+macro is similar,
+except that it just writes a terminating zero byte
+after whatever material was written by the
+.IR body .
+.PP
+The
+.BR BUF_ENCLOSE ...\&
+macros are based on lower-level machinery.
+The
+.B BUF_ENCLOSEITAG
+macro takes an additional argument
+.IR W ;
+it leaves
+.BI SZ_ W
+bytes for the length,
+checks that the length doesn't exceed
+.BI MASK W \fR,
+and stores the length using
+.BI STORE W \fR;
+all of these constants and macros are defined in
+.BR <mLib/bits.h> .
+The
+.B BUF_ENCLOSEKTAG
+is similar, except that it uses the
+.B kludge64
+machinery to handle 64-bit length fields.
+The
+.B BUF_ENCLOSEZTAG
+macro is superficially similar,
+but much simpler,
+since it all it does is write a zero byte after its
+.I body
+completes.
+All of those macros also take an additional
+.I tag
+argument
+used to scope the internal labels they construct:
+see
+.BR control (3)
+for the details on how this works.
+.PP
+The
+.B BUF_ENCLOSEITAG
+and
+.B BUF_ENCLOSEKTAG
+macros are themselves built from a lower-level macro named
+.BR BUF_ENCLOSETAG .
+In place of the
+.I W
+argument, it takes three arguments:
+.I check
+is an expression which should evaluate true if the length
+.B _delta
+can be represented;
+.I poke
+is a macro, invoked as
+.IB poke "(unsigned char *" p ", " size_t n ")" \fR,
+which should store
+.I n
+at address
+.IR p ,
+formatted in whatever way is appropriate;
+and
+.I lensz
+is the amount of space, in bytes, to save for the length.
+.
+.SS "Dynamic buffers"
+The type
+.B dbuf
+is a
+.IR "dynamic buffer" .
+It contains a buffer structure,
+accessible using the
+p.B DBUF_BUF
+macro.
+The ordinary buffer functions and macros can be used on this buffer,
+though, for convenience,
+there are similarly named functions and macros
+which accept a
+.B dbuf
+argument directly.
+There is
+.I "no difference"
+between the behaviour of the
+.B "buf"
+and
+.B "dbuf"
+functions.
+.PP
+A dynamic buffer is created by statically initializing it with
+.BR DBUF_INIT ,
+or by calling
+.BR dbuf_create
+or its macro equivalent
+.BR DBCREATE .
+The memory backing a dynamic buffer can be freed by
+.BR dbuf_destroy
+or the macro equivalent
+.BR DBDESTROY ;
+these leave the buffer in the state established by initialization:
+the buffer holds no resources, but is ready for immediate use.
+.PP
+A dynamic buffer contains an 
+.B buf
+buffer,
+called its
+.I underlying
+buffer.
+The underlying buffer is accessible through the
+.B DBUF_BUF
+macro.
+All of the above functions and macros can be applied
+to a dynamic buffer's underlying buffer.
+As a convenience,
+corresponding to each of the functions and macros described above,
+there is a version named with an initial
+.RB ` d '
+or
+.RB ` D '
+as appropriate,
+which accepts a pointer to a dynamic buffer
+rather than an ordinary buffer,
+and acts on its underlying buffer.
+Note that these functions are in no way special.
+A dynamic buffer will grow automatically
+in response to either kind of functions.
+.PP
+A freshly created buffer is in
+.I write
+mode,
+and is empty, with.
+In this state, it will automatically extend its backing storage
+in response to
+.B BENSURE
+calls, rather than breaking.
+As a result,
+an
+.I "a priori"
+unpredictable amount of data can be written to a dynamic buffer
+and it will automatically grow as necessary to accommodate it.
+Of course, the
+.B BSZ
+and
+.B BLEFT
+queries are somewhat meaningless when applied to dynamic buffers \(en
+though perfectly valid.
+The critical function for this is
+.B buf_tryextend
+(also accessible as
+.BR dbuf_tryextend )
+which attempts to arrange that at least
+.I sz
+unused bytes are available in the buffer \(en
+i.e., that
+.B BLEFT
+would return at least
+.IR sz .
+If it succeeds, it returns zero;
+it will fail if the buffer is not in write mode,
+or if the buffer is not dynamic,
+in which case it returns \-1.
+It is unlikely that applications will call this function directly.
+.PP
+The
+.B buf_flip
+(or its macro equivalent)
+switches the buffer to
+.I read
+mode,
+in addition to its usual behaviour of
+setting the buffer's limit to its current position
+and its current position to its base.
+In read mode, a dynamic buffer will no longer grow dynamically,
+as one would expect.
+.PP
+The
+.B dbuf_reset
+function,
+and its macro equivalent
+.B DBRESET
+(which may evaluate its argument multiple times)
+will return a dynamic buffer to write mode,
+and also restore its current position to its base and
+clear its broken flag.
+.
 .SH "SEE ALSO"
+.BR bits (3),
+.BR control (3),
 .BR dstr (3),
 .BR mLib (3).
+.
 .SH AUTHOR
 Mark Wooding, <mdw@distorted.org.uk>