diff --git a/include/pcp/buffer.h b/include/pcp/buffer.h index 63153f6..ef184b5 100644 --- a/include/pcp/buffer.h +++ b/include/pcp/buffer.h @@ -74,7 +74,7 @@ typedef struct _pcp_buffer Buffer; */ Buffer *buffer_new(size_t blocksize, char *name); -/** Create a new buffer. +/** Create a new string buffer. Create a new buffer, initially alloc'd to a blocksize of 32 bytes and zero-filled. The buffer will be a string buffer. See buffer_get_str(). @@ -85,6 +85,75 @@ Buffer *buffer_new(size_t blocksize, char *name); */ Buffer *buffer_new_str(char *name); + +/** Create a new buffer from existing data. + + Create a new buffer, but don't allocate memory nor copy data. + Instead the provided data pointer will be used as internal + storage directly. + + This kind of buffer can be used to put the Buffer API into + use with existing data from other sources. In most cases you'll + use it for reading. However, please be aware, that it can be + used for writing as well and in this case the data pointer + maybe resized (by calling realloc()). + + When calling buffer_free() on this Buffer, the memory pointed to + by the given data pointer will not be free'd and remains accessible. + It's the responsibility of the caller to do so. + + Example using mmap(2): + @code + #include + #include + #include + + FILE *RFD; + size_t rs; + Buffer *rb; + byte *chunk; + void *r; + + if((RFD = fopen("README", "rb")) == NULL) { + fprintf(stderr, "oops, could not open README!\n"); + return 1; + } + + fseek(RFD, 0, SEEK_END); + rs = ftell(RFD); + fseek(RFD, 0, SEEK_SET); + + void *r = mmap(NULL, rs, PROT_READ, 0, fileno(RFD), 0); + + *rb = buffer_new_buf("r", r, rs); + + size_t blocksize = 36; + void *chunk = malloc(blocksize); + + while(buffer_done(rb) != 1) { + if(buffer_left(rb) < blocksize) + blocksize = buffer_left(rb); + buffer_get_chunk(rb, chunk, blocksize); + _dump("chunk", chunk, blocksize); // or do something else with it + } + + buffer_free(rb); + + munmap(r, rs); + fclose(RFD); + @endcode + + \param[in] name A name for the Buffer. Just used for debugging purposes or in error messages. + + \param[in] data The data pointer to use by the buffer. + + \param[in] datasize The size of the data. + + \return Returns a new Buffer object. + + */ +Buffer *buffer_new_buf(char *name, void *data, size_t datasize); + /* initialize buffer vars */ void buffer_init(Buffer *b, size_t blocksize, char *name); diff --git a/libpcp/buffer.c b/libpcp/buffer.c index 571ab35..153cf7f 100644 --- a/libpcp/buffer.c +++ b/libpcp/buffer.c @@ -21,13 +21,6 @@ #include "buffer.h" -Buffer *buffer_new(size_t blocksize, char *name) { - Buffer *b = ucmalloc(sizeof(Buffer)); - b->buf = ucmalloc(blocksize); - buffer_init(b, blocksize, name); - return b; -} - void buffer_init(Buffer *b, size_t blocksize, char *name) { b->name = ucmalloc(strlen(name)+1); b->size = blocksize; @@ -39,21 +32,38 @@ void buffer_init(Buffer *b, size_t blocksize, char *name) { memcpy(b->name, name, strlen(name)+1); } +Buffer *buffer_new(size_t blocksize, char *name) { + Buffer *b = ucmalloc(sizeof(Buffer)); + b->buf = ucmalloc(blocksize); + buffer_init(b, blocksize, name); + return b; +} + Buffer *buffer_new_str(char *name) { Buffer *b = buffer_new(256, name); b->isstring = 1; return b; } +Buffer *buffer_new_buf(char *name, void *data, size_t datasize) { + Buffer *b = buffer_new(256, name); + b->allocated = 0; + b->buf = data; + b->size = datasize; + b->end = datasize; + return b; +} + void buffer_free(Buffer *b) { if(b != NULL) { if(b->allocated == 1) { + /* free the underlying data pointer only if we allocated it */ if(b->end > 0) { buffer_clear(b); - free(b->buf); } - free(b); + free(b->buf); } + free(b); } } diff --git a/tests/buffertest.c b/tests/buffertest.c index 991c305..2b3270b 100644 --- a/tests/buffertest.c +++ b/tests/buffertest.c @@ -1,6 +1,8 @@ #include "buffertest.h" +#include int main() { + /* testing basic Buffer api */ Buffer *test = buffer_new(16, "test"); byte *a = ucmalloc(32); @@ -52,6 +54,44 @@ int main() { buffer_free(test); + /* testing pointer backed buffer */ + FILE *RFD; + size_t rs; + + if((RFD = fopen("README", "rb")) == NULL) { + fprintf(stderr, "oops, could not open README!\n"); + return 1; + } + + fseek(RFD, 0, SEEK_END); + rs = ftell(RFD); + fseek(RFD, 0, SEEK_SET); + + void *r = mmap(NULL, rs, PROT_READ, 0, fileno(RFD), 0); + + //unsigned char *r = urmalloc(256); + Buffer *rb = buffer_new_buf("r", r, rs); + + fprintf(stderr, "r: %p rb->buf: %p\n", r, rb->buf); + buffer_info(rb); + + size_t blocksize = 36; + void *chunk = malloc(blocksize); + + while(buffer_done(rb) != 1) { + if(buffer_left(rb) < blocksize) + blocksize = buffer_left(rb); + buffer_get_chunk(rb, chunk, blocksize); + _dump("chunk", chunk, blocksize); + } + + buffer_free(rb); + + _dump("r", r, rs); /* should work! */ + + munmap(r, rs); + fclose(RFD); + fatals_ifany(); return 0;