/* $Cambridge: hermes/src/prayer/accountd/buffer.h,v 1.3 2003/08/07 10:53:37 dpc22 Exp $ */
/************************************************
* Prayer - a Webmail Interface *
************************************************/
/* Copyright (c) University of Cambridge 2000 - 2002 */
/* See the file NOTICE for conditions of use and distribution. */
/* Buffer
*
* Arbitary length block of data with simple sequential access methods:
*
* Append single character or block of data to end of buffer
* Rewind read offset to start of "file".
* Fetch single character or block of data from read position
*
* Typically small (< 8Kbytes). Should optimise for small buffers.
*
* Methods:
* addchar (add single character to end)
* addblock (add arbitary block of data to end)
* seek (seek to position in buffer)
* current (current offset)
* length (current length of buffer)
* getchar (fetch single character from current position, advance)
* getblock (fetch block of data from current position, advance)
*
* Propose:
* Implement using pools and linked lists to start off with
* Come back and redo using backing store files if this all works out.
*/
/* Initial implantation attempt is linked list of blocks, all same size
* Pretty simple minded, should be okay for sequential access */
struct msgblock {
struct msgblock *next;
unsigned char data[1];
};
struct buffer {
/* Global information */
struct pool *pool; /* Memory allocated from this pool */
unsigned long size; /* Size of entire file */
unsigned long offset; /* Offset into file for read methods */
unsigned long blocksize; /* Size of individual blocks */
/* Block information for append methods */
struct msgblock *first; /* First block in linked list */
struct msgblock *last; /* Final block in linked list: append here */
unsigned long avail; /* Space available in last block */
/* Block information for fetch methods */
struct msgblock *fetch; /* Current block for read access */
unsigned long fetch_avail; /* (Potential) unfetched data from block */
};
/* 8 Kbytes minus size of "next" ptr for linked list */
#define PREFERRED_BUFFER_BLOCK_SIZE (8192-sizeof(struct msgblock *))
struct buffer *buffer_create(struct pool *p, unsigned long blocksize);
void buffer_free(struct buffer *b);
unsigned long buffer_size(struct buffer *b);
void buffer_putchar(struct buffer *b, unsigned char c);
void buffer_vaprintf(struct buffer *b, char *format, va_list ap);
void buffer_printf(struct buffer *b, char *format, ...);
void buffer_puts(struct buffer *b, char *string);
void buffer_vaprintf_translate(struct buffer *b, char *fmt, va_list ap);
void buffer_printf_translate(struct buffer *b, char *fmt, ...);
void buffer_puts_translate(struct buffer *b, char *t);
/* Fetch methods */
void buffer_rewind(struct buffer *b);
int buffer_getchar(struct buffer *b);
BOOL buffer_seek_offset(struct buffer *b, unsigned long offset);
void *buffer_fetch(struct buffer *b,
unsigned long offset, unsigned long count, BOOL copy);
BOOL
buffer_fetch_block(struct buffer *b,
unsigned char **ptrp, unsigned long *sizep);
/* Macros */
#define bgetc(b) (((b->offset < b->size) && (b->fetch_avail > 0)) ? \
(b->offset++, \
b->fetch->data[b->blocksize-(b->fetch_avail--)]) : \
buffer_getchar(b))
#define bputc(b, c) \
do { \
unsigned char _c = (unsigned char)c; \
\
if (b->avail > 0) { \
b->last->data[b->blocksize-b->avail] = _c; \
b->avail--; b->size++; \
} else \
buffer_putchar(b, _c); \
} while (0)
#define bputs(a, b) buffer_puts(a, (char *)(b))
#define bprintf buffer_printf
syntax highlighted by Code2HTML, v. 0.9.1