.\" -*-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 . .\" @buf_init .\" @buf_break .\" @buf_flip .\" @buf_ensure .\" @buf_get .\" @buf_put . .\" @buf_getbyte .\" @buf_putbyte . .\" @buf_getu8 .\" @buf_getu16 .\" @buf_getu16b .\" @buf_getu16l .\" @buf_getu24 .\" @buf_getu24b .\" @buf_getu24l .\" @buf_getu32 .\" @buf_getu32b .\" @buf_getu32l . .\" @buf_putu8 .\" @buf_putu16 .\" @buf_putu16b .\" @buf_putu16l .\" @buf_putu24 .\" @buf_putu24b .\" @buf_putu24l .\" @buf_putu32 .\" @buf_putu32b .\" @buf_putu32l . .\" @buf_getbuf8 .\" @buf_getbuf16 .\" @buf_getbuf16b .\" @buf_getbuf16l .\" @buf_getbuf24 .\" @buf_getbuf24b .\" @buf_getbuf24l .\" @buf_getbuf32 .\" @buf_getbuf32b .\" @buf_getbuf32l .\" @buf_getbufz . .\" @buf_putbuf8 .\" @buf_putbuf16 .\" @buf_putbuf16b .\" @buf_putbuf16l .\" @buf_putbuf24 .\" @buf_putbuf24b .\" @buf_putbuf24l .\" @buf_putbuf32 .\" @buf_putbuf32b .\" @buf_putbuf32l .\" @buf_putbufz . .\" @buf_getmem16 .\" @buf_getmem16b .\" @buf_getmem16l .\" @buf_getmem24 .\" @buf_getmem24b .\" @buf_getmem24l .\" @buf_getmem32 .\" @buf_getmem32b .\" @buf_getmem32l .\" @buf_getmem8 .\" @buf_getmemz . .\" @buf_putmem8 .\" @buf_putmem16 .\" @buf_putmem16b .\" @buf_putmem16l .\" @buf_putmem24 .\" @buf_putmem24b .\" @buf_putmem24l .\" @buf_putmem32 .\" @buf_putmem32b .\" @buf_putmem32l .\" @buf_putmemz . .\" @buf_putstr8 .\" @buf_putstr16 .\" @buf_putstr16b .\" @buf_putstr16l .\" @buf_putstr24 .\" @buf_putstr24b .\" @buf_putstr24l .\" @buf_putstr32 .\" @buf_putstr32b .\" @buf_putstr32l .\" @buf_putstrz . .\" @buf_getdstr8 .\" @buf_getdstr16 .\" @buf_getdstr16b .\" @buf_getdstr16l .\" @buf_getdstr24 .\" @buf_getdstr24b .\" @buf_getdstr24l .\" @buf_getdstr32 .\" @buf_getdstr32b .\" @buf_getdstr32l .\" @buf_getdstrz . .\" @buf_putdstr8 .\" @buf_putdstr16 .\" @buf_putdstr16b .\" @buf_putdstr16l .\" @buf_putdstr24 .\" @buf_putdstr24b .\" @buf_putdstr24l .\" @buf_putdstr32 .\" @buf_putdstr32b .\" @buf_putdstr32l .\" @buf_putdstrz .SH SYNOPSIS .nf .B "#include " .BI "void buf_init(buf *" b ", void *" p ", size_t " sz ); .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 "int buf_break(buf *" b ); .BI "int BBAD(buf *" b ); .BI "int BOK(buf *" b ); .BI "int buf_ensure(buf *" b ", size_t " sz ); .BI "int BENSURE(buf *" b ", size_t " sz ); .BI "octet *BSTEP(buf *" b ); .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_getu" suff "(buf *" b ", uint" suff " *" w ); .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_putstr" suff "(buf *" b ", const char *" p ); .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 . .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 will break a buffer. 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 Functions which deal with block lengths assume the length is prefixed to the data, and don't include themselves. 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. .SH "SEE ALSO" .BR dstr (3), .BR mLib (3). .SH AUTHOR Mark Wooding,