summaryrefslogtreecommitdiffstats
path: root/lib/vio_fifo.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vio_fifo.h')
-rw-r--r--lib/vio_fifo.h287
1 files changed, 189 insertions, 98 deletions
diff --git a/lib/vio_fifo.h b/lib/vio_fifo.h
index 52f3455e..44f2cf47 100644
--- a/lib/vio_fifo.h
+++ b/lib/vio_fifo.h
@@ -22,152 +22,199 @@
#ifndef _ZEBRA_VIO_FIFO_H
#define _ZEBRA_VIO_FIFO_H
-#include "zebra.h"
-#include <stdint.h>
-#include <stdbool.h>
+#include "misc.h"
+#include "vargs.h"
+#include <stdio.h>
#include "list_util.h"
-#include "zassert.h"
-
-#ifndef Inline /* in case of compiler issues */
-#define Inline static inline
-#endif
-
-#ifndef Private /* extern, but for "friends" only */
-#define Private extern
-#endif
-
-/* GCC have printf type attribute check. */
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#else
-#define PRINTF_ATTRIBUTE(a,b)
-#endif /* __GNUC__ */
/*==============================================================================
* VTY I/O FIFO -- buffering of arbitrary amounts of I/O.
*/
-#ifdef NDEBUG
-# define VIO_FIFO_DEBUG 0 /* NDEBUG override */
-#else
-# ifndef VIO_FIFO_DEBUG
-# define VIO_FIFO_DEBUG 1 /* Set to 1 to turn on debug checks */
+/*------------------------------------------------------------------------------
+ * Sort out VIO_FIFO_DEBUG.
+ *
+ * Set to 1 if defined, but blank.
+ * Set to QDEBUG if not defined.
+ *
+ * Force to 0 if VIO_FIFO_NO_DEBUG is defined and not zero.
+ *
+ * So: defaults to same as QDEBUG, but no matter what QDEBUG is set to:
+ *
+ * * can set VIO_FIFO_DEBUG == 0 to turn off debug
+ * * or set VIO_FIFO_DEBUG != 0 to turn on debug
+ * * or set VIO_FIFO_NO_DEBUG != 0 to force debug off
+ */
+
+#ifdef VIO_FIFO_DEBUG /* If defined, make it 1 or 0 */
+# if IS_BLANK_OPTION(VIO_FIFO_DEBUG)
+# undef VIO_FIFO_DEBUG
+# define VIO_FIFO_DEBUG 1
+# endif
+#else /* If not defined, follow QDEBUG */
+# define VIO_FIFO_DEBUG QDEBUG
+#endif
+
+#ifdef VIO_FIFO_NO_DEBUG /* Override, if defined */
+# if IS_NOT_ZERO_OPTION(VIO_FIFO_NO_DEBUG)
+# undef VIO_FIFO_DEBUG
+# define VIO_FIFO_DEBUG 0
# endif
#endif
+enum { vio_fifo_debug = VIO_FIFO_DEBUG } ;
+
/*==============================================================================
* Data Structures
+ *
+ * Note that the main fifo structure contains the first "lump", so the fifo
+ * always contains at least one.
*/
-typedef struct vio_fifo vio_fifo_t ;
-typedef struct vio_fifo* vio_fifo ;
-
typedef struct vio_fifo_lump vio_fifo_lump_t ;
typedef struct vio_fifo_lump* vio_fifo_lump ;
+struct vio_fifo_lump
+{
+ struct dl_list_pair(vio_fifo_lump) list ;
+
+ char* end ; /* end of this particular lump */
+ char data[] ;
+} ;
+
struct vio_fifo
{
struct dl_base_pair(vio_fifo_lump) base ;
- bool one ;
+ char** p_start ; /* -> hold_ptr/get_ptr */
- char* put_ptr ;
- char* put_end ;
+ char* hold_ptr ; /* p_start == &hold_ptr <=> hold mark set */
+ /* implicitly in the head lump, if set */
+ vio_fifo_lump get_lump ; /* head lump unless "hold_ptr" */
char* get_ptr ;
- char* get_end ;
- vio_fifo_lump rdr_lump ;
- char* rdr_ptr ;
+ char** p_get_end ; /* -> lump->end/end_ptr/put_ptr */
+ char** p_end ; /* -> end_ptr/put_ptr */
+
+ vio_fifo_lump end_lump ; /* tail lump unless "end_ptr" */
+ char* end_ptr ; /* p_end == &end_ptr <=> end mark set */
+
+ char* put_ptr ; /* implicitly in the tail lump */
+ char* put_end ;
+
+ ulen size ; /* set when initialised */
- size_t size ;
+ vio_fifo_lump spare ; /* may be "own_lump" */
- vio_fifo_lump spare ;
+ vio_fifo_lump_t own_lump[] ; /* embedded lump */
} ;
-struct vio_fifo_lump
-{
- struct dl_list_pair(vio_fifo_lump) list ;
+typedef struct vio_fifo vio_fifo_t[1] ; /* embedded */
+typedef struct vio_fifo* vio_fifo ;
- char* end ; /* end of this particular lump */
- size_t size ; /* size of lump when allocated */
- char data[] ;
+/* Setting a FIFO object to all zeros is enough to initialise it to an
+ * empty FIFO (with default lump sizes).
+ */
+enum
+{
+ VIO_FIFO_INIT_ALL_ZEROS = true,
+ VIO_FIFO_DEFAULT_LUMP_SIZE = 4 * 1024
} ;
+#define VIO_FIFO_INIT_EMPTY { 0 }
+
/*==============================================================================
* Functions
*/
+extern vio_fifo vio_fifo_new(ulen size) ;
+extern vio_fifo vio_fifo_free(vio_fifo vff) ;
-extern vio_fifo vio_fifo_init_new(vio_fifo vf, size_t size) ;
-extern vio_fifo vio_fifo_reset(vio_fifo vf, int free_structure) ;
-
-#define vio_fifo_reset_keep(vf) vio_fifo_reset(vf, 0)
-#define vio_fifo_reset_free(vf) vio_fifo_reset(vf, 1)
-
-extern void vio_fifo_clear(vio_fifo vf) ;
-Inline bool vio_fifo_empty(vio_fifo vf) ;
-extern size_t vio_fifo_room(vio_fifo vf) ;
+extern void vio_fifo_clear(vio_fifo vff, bool clear_marks) ;
+Inline bool vio_fifo_empty(vio_fifo vff) ;
+Inline bool vio_fifo_tail_empty(vio_fifo vff) ;
-extern void vio_fifo_put(vio_fifo vf, const char* src, size_t n) ;
-Inline void vio_fifo_put_byte(vio_fifo vf, char b) ;
+extern void vio_fifo_put_bytes(vio_fifo vff, const char* src, ulen n) ;
+Inline void vio_fifo_put_byte(vio_fifo vff, char b) ;
-extern int vio_fifo_printf(vio_fifo vf, const char* format, ...)
+extern int vio_fifo_printf(vio_fifo vff, const char* format, ...)
PRINTF_ATTRIBUTE(2, 3) ;
-extern int vio_fifo_vprintf(vio_fifo vf, const char *format, va_list args) ;
-
-extern size_t vio_fifo_get(vio_fifo vf, void* dst, size_t n) ;
-Inline int vio_fifo_get_byte(vio_fifo vf) ;
-extern void* vio_fifo_get_lump(vio_fifo vf, size_t* have) ;
-extern void vio_fifo_got_upto(vio_fifo vf, void* here) ;
-
-Inline bool vio_fifo_full_lump(vio_fifo vf) ;
-extern int vio_fifo_write_nb(vio_fifo vf, int fd, bool all) ;
-
-extern void* vio_fifo_get_rdr(vio_fifo vf, size_t* have) ;
-extern void* vio_fifo_step_rdr(vio_fifo vf, size_t* have, size_t step) ;
-extern void vio_fifo_sync_rdr(vio_fifo vf) ;
-extern void vio_fifo_drop_rdr(vio_fifo vf) ;
-
-Private void vio_fifo_lump_new(vio_fifo vf, size_t size) ;
-Private int vio_fifo_get_next_byte(vio_fifo vf) ;
+extern int vio_fifo_vprintf(vio_fifo vff, const char *format, va_list args) ;
+extern int vio_fifo_read_nb(vio_fifo vff, int fd, ulen request) ;
+extern void vio_fifo_trim(vio_fifo vff, bool term) ;
+
+extern ulen vio_fifo_get_bytes(vio_fifo vff, void* dst, ulen n) ;
+Inline int vio_fifo_get_byte(vio_fifo vff) ;
+Inline ulen vio_fifo_get(vio_fifo vff) ;
+Inline void* vio_fifo_get_ptr(vio_fifo vff) ;
+Inline void vio_fifo_step(vio_fifo vff, ulen step) ;
+Inline ulen vio_fifo_step_get(vio_fifo vff, ulen step) ;
+
+extern vio_fifo vio_fifo_copy(vio_fifo dst, vio_fifo src) ;
+extern vio_fifo vio_fifo_copy_tail(vio_fifo dst, vio_fifo src) ;
+
+extern int vio_fifo_write_nb(vio_fifo vff, int fd, bool all) ;
+extern int vio_fifo_fwrite(vio_fifo vff, FILE* file) ;
+
+extern void vio_fifo_skip_to_end(vio_fifo vff) ;
+extern void vio_fifo_set_end_mark(vio_fifo vff) ;
+extern void vio_fifo_step_end_mark(vio_fifo vff) ;
+extern void vio_fifo_clear_end_mark(vio_fifo vff) ;
+extern void vio_fifo_back_to_end_mark(vio_fifo vff, bool keep) ;
+extern void vio_fifo_set_hold_mark(vio_fifo vff) ;
+extern void vio_fifo_clear_hold_mark(vio_fifo vff) ;
+extern void vio_fifo_back_to_hold_mark(vio_fifo vff, on_off_b on) ;
/*==============================================================================
* Debug -- verification function
*/
-Private void vio_fifo_verify(vio_fifo vf) ;
+Private void vio_fifo_verify(vio_fifo vff) ;
-#if VIO_FIFO_DEBUG
-# define VIO_FIFO_DEBUG_VERIFY(vf) vio_fifo_verify(vf)
-#else
-# define VIO_FIFO_DEBUG_VERIFY(vf)
-#endif
+#define VIO_FIFO_DEBUG_VERIFY(vff) if (vio_fifo_debug) vio_fifo_verify(vff)
/*==============================================================================
* Inline Functions
*/
+Private void vio_fifo_add_lump(vio_fifo vff) ;
+Private void vio_fifo_sync_get(vio_fifo vff) ;
+
+/*------------------------------------------------------------------------------
+ * Returns true <=> FIFO is empty -- at least: get_ptr == end_ptr (if any)
+ * or: get_ptr == put_ptr.
+ */
+Inline bool
+vio_fifo_empty(vio_fifo vff)
+{
+ return (vff == NULL) || (vff->get_ptr == *vff->p_end) ;
+} ;
+
/*------------------------------------------------------------------------------
- * Returns true <=> FIFO is empty
+ * Returns true <=> FIFO is empty beyond end_ptr (if any).
*/
Inline bool
-vio_fifo_empty(vio_fifo vf)
+vio_fifo_tail_empty(vio_fifo vff)
{
- return (vf->get_ptr == vf->put_ptr) ;
-}
+ /* if vff is NULL, treat as empty !
+ * if end_ptr is NULL, then tail is empty !
+ * else tail is empty iff end_ptr == put_ptr.
+ */
+ return (vff == NULL) || (vff->put_ptr == *vff->p_end) ;
+} ;
/*------------------------------------------------------------------------------
* Put one byte to the FIFO
*/
Inline void
-vio_fifo_put_byte(vio_fifo vf, char b)
+vio_fifo_put_byte(vio_fifo vff, char b)
{
- if (vf->put_ptr >= vf->put_end)
- vio_fifo_lump_new(vf, vf->size) ; /* traps put_ptr > put_end */
+ if (vff->put_ptr >= vff->put_end)
+ vio_fifo_add_lump(vff) ; /* traps put_ptr > put_end */
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
- *vf->put_ptr++ = b ;
+ *vff->put_ptr++ = b ;
} ;
/*------------------------------------------------------------------------------
@@ -177,29 +224,73 @@ vio_fifo_put_byte(vio_fifo vf, char b)
* -1 => FIFO is empty.
*/
Inline int
-vio_fifo_get_byte(vio_fifo vf)
+vio_fifo_get_byte(vio_fifo vff)
{
- if (vf->get_end <= (vf->get_ptr + 1))
- return vio_fifo_get_next_byte(vf) ;
+ if (vff->get_ptr < *vff->p_get_end)
+ {
+ int ch ;
+ ch = (uchar)*vff->get_ptr ;
+
+ vio_fifo_step(vff, 1) ;
- VIO_FIFO_DEBUG_VERIFY(vf) ;
+ return ch ;
+ }
- return (unsigned char)*vf->get_ptr++ ;
+ return -1 ;
} ;
/*------------------------------------------------------------------------------
- * See if have at least one full lump.
+ * Get count of bytes available in the current lump.
*
- * This may be used with vio_fifo_write_nb(..., false) to use FIFO as a sort of
- * double buffer.
+ * There will always be at least 1 byte available in the current lump, unless
+ * the FIFO is empty, or at the end mark.
*
- * Returns: true <=> there is at least one full lump in the FIFO
- * (excluding the last lump if it happens to be full)
+ * Returns: address of bytes to get
*/
-Inline bool
-vio_fifo_full_lump(vio_fifo vf)
+Inline ulen
+vio_fifo_get(vio_fifo vff)
+{
+ return *vff->p_get_end - vff->get_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get pointer to bytes in the current lump.
+ *
+ * NB: to be called only after vio_fifo_get(), or vio_fifo_steo_get() have
+ * returned a non-zero value.
+ */
+Inline void*
+vio_fifo_get_ptr(vio_fifo vff)
+{
+ return vff->get_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Step FIFO past bytes used.
+ *
+ * Can be called after a vio_fifo_get() or vio_fifo_step_get().
+ *
+ * NB: the "step" argument MUST not exceed the "have" previously returned.
+ */
+Inline void
+vio_fifo_step(vio_fifo vff, ulen step)
+{
+ vff->get_ptr += step ;
+
+ if (vff->get_ptr >= *vff->p_get_end)
+ vio_fifo_sync_get(vff) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vff) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * vio_fifo_step() forllowed by vio_fifo_get() !
+ */
+Inline ulen
+vio_fifo_step_get(vio_fifo vff, ulen step)
{
- return (!vf->one && (vf->put_ptr != NULL)) ;
+ vio_fifo_step(vff, step) ;
+ return vio_fifo_get(vff) ;
} ;
#endif /* _ZEBRA_VIO_FIFO_H */