#include "mawk.h"

#define MAWK_ZFIFO_STAGE 64

/* zmalloc based binary fifo; a linked list of zmalloc'd blocks of writes.
   Small writes are cached until they reach MAWK_ZFIFO_STAGE to avoid a lot
   of blocks when writing the fifo char-by-char */

typedef struct mawk_zfifo_block_s mawk_zfifo_block_t;

struct mawk_zfifo_block_s {
	mawk_zfifo_block_t *next; /* next block to jump to when this one is exhausted */
	int size;
	int readp;                /* next character to read from this buffer */
	char buf[1];              /* start of the buffer */
};

typedef struct {
	int size, max_size;               /* current and maximum size; max size is in data bytes hold by the buffer, there's an overhead of allocation; max_size = -1 means no limit */
	char stage_buf[MAWK_ZFIFO_STAGE]; /* staging: buffer small writes to avoid very small zmalloc(); this also assumes read happens in bigger chunks so stage buffer is most likely read at once */
	int stage_used;
	mawk_zfifo_block_t *head, *tail;  /* singly linked list of blocks with head and tail */
	int zalloced;                     /* whether the fifo was zalloc()'d */
} mawk_zfifo_t;

/* set up fifo; if sfifo is NULL, the fifo is zalloc()'d, else all fields
   are reset */
mawk_zfifo_t *mawk_zfifo_alloc(mawk_state_t *MAWK, mawk_zfifo_t *sfifo, int max_size);

/* discard all data and free the buffer; if it was auto-zalloc()'d
   in mawk_zfifo_alloc(), fifo is zfree()d here */
void mawk_zfifo_free(mawk_state_t *MAWK, mawk_zfifo_t *fifo);

/* append data to the end of a fifo; return size written
   (no short write: if max_size prevents the write, no bytes are appended and 0 is returned) */
int mawk_zfifo_write(mawk_state_t *MAWK, mawk_zfifo_t *fifo, const char *data, int size);

/* pop data from the beginning of the fifo; return size read
   (short read: when there's not enough data in the fifo) */
int mawk_zfifo_read(mawk_state_t *MAWK, mawk_zfifo_t *fifo, char *data, int size);

