/* * RINGBUF - general support for ring buffers * * Author: * Emile van Bergen, emile@evbergen.xs4all.nl * * Permission to redistribute an original or modified version of this program * in source, intermediate or object code form is hereby granted exclusively * under the terms of the GNU General Public License, version 2. Please see the * file COPYING for details, or refer to http://www.gnu.org/copyleft/gpl.html. * * History: * 2000/11/28 - EvB - Created * 2001/01/09 - EvB - Added ring_capacity inline function * - Made the header a little more readable * 2001/07/02 - EvB - Added ring_peekdata * 2001/07/03 - EvB - Added ring_strncmp as a counting function */ #ifndef __RINGBUF_H #define __RINGBUF_H 1 /* * INCLUDES & DEFINES */ #include /* for ssize_t */ #include /* for va_list */ /* Return status for ring_read and ring_write */ #define RING_OK 0 #define RING_EOF 1 /* if we read/wrote less than requested */ #define RING_IOERR 2 /* if the operation returned -1 */ #define RING_EAGAIN 4 /* if error but errno was eagain */ #ifndef __GNUC__ #define __inline__ /* */ #endif /* * TYPES */ /* The ring object itself */ typedef struct ring { ssize_t size, r, w; char *buf; } RING; /* Counting function for peeks */ typedef ssize_t (*RINGCNTFUNC)(char *s, ssize_t len, ssize_t seen, va_list ap); /* * PROTOTYPES */ /* * Creation / deletion */ RING *ring_new(ssize_t size); void ring_del(RING *r); /* * Debugging */ void ring_debug(RING *r); /* * Getting / putting */ /* Get data from the ring. Returns number of bytes removed. */ ssize_t ring_get(RING *r, void *data, ssize_t len); ssize_t ring_peekdata(RING *r, void *data, ssize_t len); /* Add data to the ring. Returns number of bytes added. */ ssize_t ring_put(RING *r, void *data, ssize_t len); /* Discard data from the ring. Returns number of bytes removed. If maxlen == 0, discards all. */ ssize_t ring_discard(RING *r, ssize_t maxlen); /* * Open file I/O */ #if 0 /* Old interface */ /* Get data from the ring and write it to an open file. Returns number of bytes written, 0 if no data was available in the ring, or -1 if a write error occured. If min > 0, specifies the minimum amount of data that must be available before trying to write. If max > 0, specifies the maximum amount of data that may be written at once. */ ssize_t ring_write(RING *r, int fd, ssize_t min, ssize_t max); /* Read data from and open file and add it to the ring. Returns number of bytes added, 0 if no data was read from the file, either due to EOF or lack of buffer space, or -1 if a write error occured. If min > 0, specifies the minimum amount of data that must be available before trying to write. If max > 0, specifies a maximum amount of data to read. */ ssize_t ring_read(RING *r, int fd, ssize_t min, ssize_t max); #else int ring_read(RING *r, int fd, ssize_t *xfered); int ring_write(RING *r, int fd, ssize_t *xfered, ssize_t max); #endif /* * Scanning functions; return the number of characters avaliable that * satisfies a certain condition */ /* General function */ ssize_t ring_count(RING *r, RINGCNTFUNC func, ...); /* Counting functions for use with ring_count */ ssize_t _ring_cnt_strspn(char *s, ssize_t len, ssize_t seen, va_list ap); ssize_t _ring_cnt_strcspn(char *s, ssize_t len, ssize_t seen, va_list ap); ssize_t _ring_cnt_strncmp(char *s, ssize_t len, ssize_t seen, va_list ap); /* * VARIOUS INLINED FUNCTIONS */ #if 0 /* Scanning functions built with ring_count and the counting functions */ /* strlen, but returns ring_maxget if no end found */ extern __inline__ ssize_t ring_strlen(RING *r) { return ring_count(r, _ring_cnt_strcspn, "\0", 1); } /* strspn, but takes a string with length */ extern __inline__ ssize_t ring_strspn(RING *r, char *s, int slen) { return ring_count(r, _ring_cnt_strspn, s, slen); } /* strcspn, but takes a string with length */ extern __inline__ ssize_t ring_strcspn(RING *r, char *s, int slen) { return ring_count(r, _ring_cnt_strcspn, s, slen); } /* strncmp, but always returns 1 if different, ignores relative position */ extern __inline__ ssize_t ring_strncmp(RING *r, char *s, int slen) { return ring_count(r, _ring_cnt_strncmp, s, slen) != slen; } /* * Testing functions */ /* Put is guaranteed to accept the number of bytes returned by maxput */ extern __inline__ ssize_t ring_maxput(RING *r) { return ((r->size + (r->r - (r->w + 1))) % r->size); } /* Get is guaranteed to give the number of bytes returned by maxget. */ extern __inline__ ssize_t ring_maxget(RING *r) { return ((r->size + (r->w - r->r)) % r->size); } /* Check if the ring is empty */ extern __inline__ int ring_isempty(RING *r) { return (r->r == r->w); } /* Check if the ring is full */ extern __inline__ int ring_isfull(RING *r) { return ring_maxput(r) == 0; } /* Get the full capacity of the ring, which is the size minus the guard byte that makes it possible to distinguish between a full and an empty ring. */ extern __inline__ int ring_capacity(RING *r) { return r->size - 1; } /* Peeking function */ /* Look at the single character at the specified position in the string of available bytes. If a position beyond the end of that string is specified, -1 is returned. */ extern __inline__ int ring_peek(RING *r, ssize_t pos) { if (pos >= 0 && pos < ring_maxget(r)) { return (r->buf[(r->size + r->r + pos) % r->size]) & 0xff; } return -1; } #endif /* Derived testing macros */ #define ring_strlen(r) ring_count((r), _ring_cnt_strcspn, "\0", 1) #define ring_strspn(r, s, slen) ring_count((r), _ring_cnt_strspn, (s), (slen)) #define ring_strcspn(r, s, slen) ring_count((r), _ring_cnt_strcspn, (s), (slen)) /* always returns 1 if different - doesn't test bigger or smaller */ #define ring_strncmp(r, s, slen) (ring_count((r), _ring_cnt_strncmp, \ (s), (slen)) != (slen)) /* Testing; put is guaranteed to accept the number of bytes given by maxput, and get is guaranteed to return the number of bytes given by maxget. These are also available in the header as inlines. */ #define ring_maxput(R) (((R)->size + ((R)->r - ((R)->w + 1))) % (R)->size) #define ring_maxget(R) (((R)->size + ((R)->w - (R)->r)) % (R)->size) #define ring_isempty(R) ((R)->r == (R)->w) #define ring_capacity(R) ((R)->size - 1) /* Peeking function: returns the single character at the specified position in the string of available bytes. If a position beyond the end of that string is specified, -1 is returned. This function is also available inline in the header. */ #define ring_peek(R, POS) ( \ ((POS) >= 0 && (POS) < ring_maxget((R))) ? \ ((R)->buf[((R)->size + (R)->r + (POS)) % (R)->size]) & 0xff : \ -1) #endif /* ndef __RINGBUF_H */