1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
/* $Cambridge: hermes/src/prayer/lib/buffer.h,v 1.3 2008/09/16 09:59:57 dpc22 Exp $ */
/************************************************
* Prayer - a Webmail Interface *
************************************************/
/* Copyright (c) University of Cambridge 2000 - 2008 */
/* 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);
void buffer_reset(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
void buffer_encode_url(struct buffer *b, char *s);
void buffer_encode_canon(struct buffer *b, char *s);
|