.\" -*-nroff-*- .de VS .sp 1 .RS .nf .ft B .. .de VE .ft R .fi .RE .sp 1 .. .de hP .IP .ft B \h'-\w'\\$1\ 'u'\\$1\ \c .ft P .. .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 .\" @BLIM .\" @BCUR .\" @BSZ .\" @BLEN .\" @BLEFT .\" @BSTEP .\" @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 .\" @buf_getu16b .\" @buf_getu16l .\" @buf_getu24 .\" @buf_getu24b .\" @buf_getu24l .\" @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 .\" @buf_putu16b .\" @buf_putu16l .\" @buf_putu24 .\" @buf_putu24b .\" @buf_putu24l .\" @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 .\" @buf_getbuf16b .\" @buf_getbuf16l .\" @buf_getbuf24 .\" @buf_getbuf24b .\" @buf_getbuf24l .\" @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 .\" @buf_putbuf16b .\" @buf_putbuf16l .\" @buf_putbuf24 .\" @buf_putbuf24b .\" @buf_putbuf24l .\" @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 .\" @buf_getmem24 .\" @buf_getmem24b .\" @buf_getmem24l .\" @buf_getmem32 .\" @buf_getmem32b .\" @buf_getmem32l .\" @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 .\" @buf_putmem16b .\" @buf_putmem16l .\" @buf_putmem24 .\" @buf_putmem24b .\" @buf_putmem24l .\" @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 .\" @buf_putstr16b .\" @buf_putstr16l .\" @buf_putstr24 .\" @buf_putstr24b .\" @buf_putstr24l .\" @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 .\" @buf_getdstr16b .\" @buf_getdstr16l .\" @buf_getdstr24 .\" @buf_getdstr24b .\" @buf_getdstr24l .\" @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 .\" @buf_putdstr16b .\" @buf_putdstr16l .\" @buf_putdstr24 .\" @buf_putdstr24b .\" @buf_putdstr24l .\" @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 " .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 ); .BI "octet *BCUR(buf *" b ); .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 ); .BI "void *buf_get(buf *" b ", size_t " sz ); .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_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 "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 .I base The base address of the buffer. .TP .I limit Just past the last usable byte in the buffer .TP .I current The position in the buffer at which the next read or write will occur. .PP A buffer is created using the .B buf_init function. You must pass it the buffer base address and size, and a pointer to a .B buf structure to fill in. It doesn't allocate any memory, so you don't need to dispose of the .B buf structure in any way before forgetting about it. .PP A collection of macros is provided for finding the positions of the various interesting pointers known about a buffer, and the sizes of the regions of memory they imply. .TP .B BBASE The buffer's .I base pointer. .TP .B BLIM The buffer's .I limit pointer. .TP .B BCUR The buffer's .I current pointer. .TP .B BSZ The size of the buffer; i.e., .I limit \- .IR base . .TP .B BLEN The length of data in the buffer (if writing) or the amount of data read (if reading); i.e., .I current \- .IR base . .TP .B BLEFT The amount of space left in the buffer (if writing) or the amount of data yet to read (if reading); i.e., .I limit \- .IR current . .PP The function .B buf_flip takes a buffer which has been used for writing, and makes it suitable for reading. This turns out to be useful when building packets in multi-layered networking software. Its precise behaviour is to preserve .IR base , to set .I limit to .IR current , 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 , to indicate that it has overflowed or that its contents are otherwise invalid. The various buffer access functions described below all fail on a broken buffer, and any errors they encounter cause the buffer to become broken. Most simple programs which only use the supplied buffer access functions can avoid the tedium of error-checking every function call and just check the brokenness state at the end of their run. .PP The function .B buf_break 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 macro (or the equivalent .B buf_ensure function) checks that the buffer is OK and that there is enough space remaining in the buffer for .I sz bytes: if so, it returns zero; otherwise it breaks the buffer and returns \-1. .PP The .B BSTEP macro advances the buffer's .I current pointer by .I sz bytes. It does no bounds checking. Together with .BR BENSURE , this provides sequential access to the buffer's contents. .PP The .B buf_get function is the basis of most buffer access functions, whether for reading or writing. If the buffer is OK, and there are .I sz or more bytes remaining, it steps the buffer's .I current pointer by .I sz and returns the .I original (pre-stepping) .I current pointer; otherwise it breaks the buffer if necessary, and returns a null pointer. .PP The .B buf_put function writes .I sz 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 returns the next byte from a buffer as a nonnegative integer, or \-1 on error. The function .B buf_putbyte writes its argument to a buffer, and returns 0 on succes; it returns \-1 if it failed. .PP Many of the remaining functions deal with integer formatting and buffer lengths. The functions support 8-, 16-, 24- and 32-bit integers, in big- or little-endian order; on platforms with 64-bit integers, these are supported too. The functions' names carry a suffix which is the width in bits of the integers they deal with and an optional .RB ` l ' for little- or .RB ` b ' for big-endian byte order. (The variant with no letter uses big-endian order. Use of these variants tends to mean `I don't really care, but be consistent,' and is not recommended if you have an externally-defined spec you're meant to be compatible with.) .PP The function .BI buf_getu suff reads an integer. On success, it stores the integer it read at the address .I w 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 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. .PP The function .BI buf_getmem suff fetches a block of data. On success, it returns its base address and stores its length at the given address; on failure, it returns null. The function .BI buf_putmem suff writes a block of data; it return zero on success or \-1 on failure. .PP The functon .BI buf_getbuf suff fetches a block of data and makes a second buffer point to it, i.e., setting its .I base and .I current pointers to the start of the block and its .I limit pointer to just past the end. No copying of bulk data is performed. The function .BI buf_putbuf suff writes the contents of a buffer (i.e., between its .I base and .I current pointers). The function .BI buf_getdstr suff fetches a block of data and append it to a dynamic string (see .BR dstr (3)). The function .BI buf_putdstr suff writes the contents of a dynamic string to a buffer. Finally, the 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 . 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,