Tue, 13 Aug 2013 14:20:12 +0200
completed documentation + changed API for buffer/stream generic copy functions
test/buffer_tests.c | file | annotate | diff | comparison | revisions | |
test/buffer_tests.h | file | annotate | diff | comparison | revisions | |
test/main.c | file | annotate | diff | comparison | revisions | |
ucx/buffer.c | file | annotate | diff | comparison | revisions | |
ucx/buffer.h | file | annotate | diff | comparison | revisions | |
ucx/utils.c | file | annotate | diff | comparison | revisions | |
ucx/utils.h | file | annotate | diff | comparison | revisions |
--- a/test/buffer_tests.c Mon Aug 12 14:43:22 2013 +0200 +++ b/test/buffer_tests.c Tue Aug 13 14:20:12 2013 +0200 @@ -27,6 +27,7 @@ */ #include "buffer_tests.h" +#include "ucx/utils.h" UCX_TEST(test_ucx_buffer_seektell) { UcxBuffer *b = ucx_buffer_new(NULL, 32, UCX_BUFFER_DEFAULT); @@ -292,7 +293,7 @@ ucx_buffer_free(src); } -UCX_TEST(test_ucx_buffer_generic_copy) { +UCX_TEST(test_ucx_stream_copy) { UcxBuffer *b1 = ucx_buffer_new(NULL, 64, UCX_BUFFER_DEFAULT); UcxBuffer *b2 = ucx_buffer_new(NULL, 2, UCX_BUFFER_AUTOEXTEND); @@ -303,7 +304,7 @@ UCX_TEST_ASSERT(b1->size == 16, "failed to fill buffer b1"); ucx_buffer_seek(b1, 0, SEEK_SET); - size_t ncp = ucx_buffer_copy(b1, b2, ucx_buffer_read, ucx_buffer_write); + size_t ncp = ucx_stream_hcopy(b1, b2, ucx_buffer_read, ucx_buffer_write); UCX_TEST_ASSERT(ncp == 16, "wrong number of copied bytes"); UCX_TEST_ASSERT(b2->size == 16, "b2 has wrong size"); UCX_TEST_ASSERT(memcmp(b1->space, b2->space, 16) == 0, @@ -317,19 +318,25 @@ FILE *file = tmpfile(); UCX_TEST_ASSERT(file, "test file cannot be opened, test aborted"); - ncp = ucx_buffer_copy(b1, file, ucx_buffer_read, fwrite); + ncp = ucx_stream_hcopy(b1, file, ucx_buffer_read, fwrite); UCX_TEST_ASSERT(ncp == 16, "copied wrong number of bytes to file"); fseek(file, 0, SEEK_SET); - ncp = ucx_buffer_copy(file, b2, fread, ucx_buffer_write); + ncp = ucx_stream_hcopy(file, b2, fread, ucx_buffer_write); UCX_TEST_ASSERT(ncp == 16, "copied wrong number of bytes from file"); UCX_TEST_ASSERT(memcmp(b1->space, b2->space, 16) == 0, "b1 and b2 content mismatch"); fclose(file); - + + ucx_buffer_clear(b1); + ucx_buffer_seek(b2, 0, SEEK_SET); + ncp = ucx_stream_ncopy(b2, b1, ucx_buffer_read, ucx_buffer_write, 8); + UCX_TEST_ASSERT(ncp == 8, "copied wrong number of bytes with ncopy"); + UCX_TEST_ASSERT(memcmp(b1->space, "01234567\0\0\0\0\0\0\0\0", 16) == 0, + "content wrong after ncopy"); UCX_TEST_END
--- a/test/buffer_tests.h Mon Aug 12 14:43:22 2013 +0200 +++ b/test/buffer_tests.h Tue Aug 13 14:20:12 2013 +0200 @@ -46,7 +46,7 @@ UCX_TEST(test_ucx_buffer_write_ax); UCX_TEST(test_ucx_buffer_read); UCX_TEST(test_ucx_buffer_extract); -UCX_TEST(test_ucx_buffer_generic_copy); +UCX_TEST(test_ucx_stream_copy); #ifdef __cplusplus }
--- a/test/main.c Mon Aug 12 14:43:22 2013 +0200 +++ b/test/main.c Tue Aug 13 14:20:12 2013 +0200 @@ -176,7 +176,7 @@ ucx_test_register(suite, test_ucx_buffer_write_ax); ucx_test_register(suite, test_ucx_buffer_read); ucx_test_register(suite, test_ucx_buffer_extract); - ucx_test_register(suite, test_ucx_buffer_generic_copy); + ucx_test_register(suite, test_ucx_stream_copy); ucx_test_run(suite, stdout); fflush(stdout);
--- a/ucx/buffer.c Mon Aug 12 14:43:22 2013 +0200 +++ b/ucx/buffer.c Tue Aug 13 14:20:12 2013 +0200 @@ -91,17 +91,16 @@ } int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) { - size_t npos = 0; + size_t npos; switch (whence) { - case SEEK_SET: - npos = 0; - break; case SEEK_CUR: npos = buffer->pos; break; case SEEK_END: npos = buffer->size; break; + default: + npos = 0; } npos += offset; @@ -210,51 +209,6 @@ } } -size_t ucx_buffer_generic_copy(void *s1, void *s2, - read_func readfnc, write_func writefnc, size_t bufsize) { - size_t ncp = 0; - char *buf = (char*)malloc(bufsize); - if(buf == NULL) { - return 0; - } - - size_t r; - while((r = readfnc(buf, 1, bufsize, s1)) != 0) { - r = writefnc(buf, 1, r, s2); - ncp += r; - if(r == 0) { - break; - } - } - - free(buf); - return ncp; +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) { + return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); } - -size_t ucx_buffer_generic_ncopy(void *s1, void *s2, - read_func readfnc, write_func writefnc, size_t bufsize, size_t n) { - if(n == 0) { - return 0; - } - - size_t ncp = 0; - char *buf = (char*)malloc(bufsize); - if(buf == NULL) { - return 0; - } - - size_t r; - size_t rn = bufsize > n ? n : bufsize; - while((r = readfnc(buf, 1, rn, s1)) != 0) { - r = writefnc(buf, 1, r, s2); - ncp += r; - n -= r; - rn = bufsize > n ? n : bufsize; - if(r == 0 || n == 0) { - break; - } - } - - free(buf); - return ncp; -}
--- a/ucx/buffer.h Mon Aug 12 14:43:22 2013 +0200 +++ b/ucx/buffer.h Tue Aug 13 14:20:12 2013 +0200 @@ -26,6 +26,23 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/** + * @file buffer.h + * + * Advanced buffer implementation. + * + * Instances of UcxBuffer can be used to read from or to write to like one + * would do with a stream. This allows the use of ucx_stream_copy() to copy + * contents from one buffer to another. + * + * Some features for convenient use of the buffer + * can be enabled. See the documentation of the macro constants for more + * information. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + #ifndef UCX_BUFFER_H #define UCX_BUFFER_H @@ -37,94 +54,208 @@ extern "C" { #endif -/* no autoextend or autofree behaviour */ +/** + * No buffer features enabled (all flags cleared). + */ #define UCX_BUFFER_DEFAULT 0x00 -/* the buffer shall free the occupied memory space */ +/** + * If this flag is enabled, the buffer will automatically free its contents. + */ #define UCX_BUFFER_AUTOFREE 0x01 -/* the buffer may automatically double its size on write operations */ +/** + * If this flag is enabled, the buffer will automatically extends its capacity. + */ #define UCX_BUFFER_AUTOEXTEND 0x02 -/* the user shall not modify values, but may get the latest pointer */ +/** UCX Buffer. */ typedef struct { + /** A pointer to the buffer contents. */ char *space; + /** Current position of the buffer. */ size_t pos; + /** Current capacity (i.e. maximum size) of the buffer. */ size_t capacity; + /** Current size of the buffer content. */ size_t size; + /** + * Flag register for buffer features. + * @see #UCX_BUFFER_DEFAULT + * @see #UCX_BUFFER_AUTOFREE + * @see #UCX_BUFFER_AUTOEXTEND + */ int flags; } UcxBuffer; -/* if space is NULL, new space is allocated and the autofree flag is enforced */ +/** + * Creates a new buffer. + * + * <b>Note:</b> you may provide <code>NULL</code> as argument for + * <code>space</code>. Then this function will allocate the space and enforce + * the #UCX_BUFFER_AUTOFREE flag. + * + * @param space pointer to the memory area, or <code>NULL</code> to allocate + * new memory + * @param size the size of the buffer + * @param flags buffer features (see UcxBuffer.flags) + * @return the new buffer + */ UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags); + +/** + * Destroys a buffer. + * + * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer + * are also freed. + * + * @param buffer the buffer to destroy + */ void ucx_buffer_free(UcxBuffer* buffer); -/* - * the autofree flag is enforced for the new buffer - * if length is zero, the whole remaining buffer shall be extracted - * the position of the new buffer is set to zero +/** + * Creates a new buffer and fills it with extracted content from another buffer. + * + * <b>Note:</b> the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. + * + * @param src the source buffer + * @param start the start position of extraction + * @param length the count of bytes to extract or 0 if all of the remaining + * bytes shall be extracted + * @param flags feature mask for the new buffer + * @return */ UcxBuffer* ucx_buffer_extract(UcxBuffer *src, size_t start, size_t length, int flags); + +/** + * A shorthand macro for the full extraction of the buffer. + * + * @param src the source buffer + * @param flags feature mask for the new buffer + * @return a new buffer with the extracted content + */ #define ucx_buffer_clone(src,flags) \ ucx_buffer_extract(src, 0, 0, flags) -/* - * Moves the position of the buffer to a new position relative to whence. +/** + * Moves the position of the buffer. + * + * The new position is relative to the <code>whence</code> argument. * - * SEEK_SET marks the start of the buffer - * SEEK_CUR marks the current position - * SEEK_END marks the first 0-byte in the buffer - * - * ucx_buffer_seek returns 0 on success and -1 if the new position is beyond the - * bounds of the allocated buffer. In that case the position of the buffer - * remains unchanged. + * SEEK_SET marks the start of the buffer. + * SEEK_CUR marks the current position. + * SEEK_END marks the first 0-byte in the buffer. + * + * @param buffer + * @param offset position offset relative to <code>whence</code> + * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END + * @return 0 on success, non-zero if the position is invalid * */ int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); -#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ - buffer->size = 0; buffer->pos = 0; +/** + * Clears the buffer by resetting the position and deleting the data. + * + * The data is deleted by a zeroing it with call to <code>memset()</code>. + * + * @param buffer the buffer to be cleared + */ +#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ + buffer->size = 0; buffer->pos = 0; -/* - * returns non-zero, if the current buffer position has exceeded the last - * available byte of the underlying buffer - * +/** + * Tests, if the buffer position has exceeded the buffer capacity. + * + * @param buffer the buffer to test + * @return non-zero, if the current buffer position has exceeded the last + * available byte of the buffer. */ int ucx_buffer_eof(UcxBuffer *buffer); -int ucx_buffere_extend(UcxBuffer *buffer, size_t len); +/** + * Extends the capacity of the buffer. + * + * <b>Note:</b> The buffer capacity increased by a power of two. I.e. + * the buffer capacity is doubled, as long as it would not hold the current + * content plus the additional required bytes. + * + * <b>Attention:</b> the argument provided is the count of <i>additional</i> + * bytes the buffer shall hold. It is <b>NOT</b> the total count of bytes the + * buffer shall hold. + * + * @param buffer the buffer to extend + * @param additional_bytes the count of additional bytes the buffer shall + * <i>at least</i> hold + * @return 0 on success or a non-zero value on failure + */ +int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); +/** + * Writes data to an UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area containing the bytes to be written + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to write to + * @return the total count of bytes written + */ size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, UcxBuffer *buffer); +/** + * Reads data from an UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area where to store the read data + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to read from + * @return the total count of bytes read + */ size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, UcxBuffer *buffer); -int ucx_buffer_putc(UcxBuffer *b, int c); -int ucx_buffer_getc(UcxBuffer *b); - - -/* - * copies all bytes from s1 to s2 - * uses the read function r to read from s1 und writes the data using the - * write function w to s2 - * returns the number of bytes copied +/** + * Writes a character to a buffer. + * + * The least significant byte of the argument is written to the buffer. If the + * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, + * the buffer capacity is extended by ucx_buffer_extend(). If the feature is + * disabled or buffer extension fails, <code>EOF</code> is returned. + * + * On successful write the position of the buffer is increased. + * + * @param buffer the buffer to write to + * @param c the character to write as <code>int</code> value + * @return the byte that has bean written as <code>int</code> value or + * <code>EOF</code> when the end of the stream is reached and automatic + * extension is not enabled or not possible */ -size_t ucx_buffer_generic_copy(void *s1, void *s2, read_func r, write_func w, - size_t bufsize); +int ucx_buffer_putc(UcxBuffer *buffer, int c); -size_t ucx_buffer_generic_ncopy(void *s1, void *s2, read_func r, write_func w, - size_t bufsize, size_t n); - -#define UCX_DEFAULT_BUFFER_SIZE 0x1000 +/** + * Gets a character from a buffer. + * + * The current position of the buffer is increased after a successful read. + * + * @param buffer the buffer to read from + * @return the character as <code>int</code> value or <code>EOF</code>, if the + * end of the buffer is reached + */ +int ucx_buffer_getc(UcxBuffer *buffer); -#define ucx_buffer_copy(s1,s2,r,w) \ - ucx_buffer_generic_copy(s1, s2, (read_func)r, (write_func)w, \ - UCX_DEFAULT_BUFFER_SIZE) - -#define ucx_buffer_ncopy(s1,s2,r,w, n) \ - ucx_buffer_generic_ncopy(s1, s2, (read_func)r, (write_func)w, \ - UCX_DEFAULT_BUFFER_SIZE, n) +/** + * Writes a string to a buffer. + * + * @param buffer the buffer + * @param str the string + * @return the number of bytes written + */ +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); #ifdef __cplusplus }
--- a/ucx/utils.c Mon Aug 12 14:43:22 2013 +0200 +++ b/ucx/utils.c Tue Aug 13 14:20:12 2013 +0200 @@ -27,7 +27,7 @@ */ #include "utils.h" -#include "math.h" +#include <math.h> /* COPY FUCNTIONS */ void* ucx_strcpy(void* s, void* data) { @@ -45,6 +45,36 @@ return cpy; } +size_t ucx_stream_copy(void *src, void *dest, read_func readfnc, + write_func writefnc, char* buf, size_t bufsize, size_t n) { + if(n == 0 || bufsize == 0) { + return 0; + } + + size_t ncp = 0; + if (!buf) { + buf = (char*)malloc(bufsize); + if(buf == NULL) { + return 0; + } + } + + size_t r; + size_t rn = bufsize > n ? n : bufsize; + while((r = readfnc(buf, 1, rn, src)) != 0) { + r = writefnc(buf, 1, r, dest); + ncp += r; + n -= r; + rn = bufsize > n ? n : bufsize; + if(r == 0 || n == 0) { + break; + } + } + + free(buf); + return ncp; +} + /* COMPARE FUNCTION */ int ucx_strcmp(void *s1, void *s2, void *data) {
--- a/ucx/utils.h Mon Aug 12 14:43:22 2013 +0200 +++ b/ucx/utils.h Tue Aug 13 14:20:12 2013 +0200 @@ -43,6 +43,7 @@ #endif #include "ucx.h" +#include <stdint.h> #include <string.h> /** @@ -62,6 +63,50 @@ */ void *ucx_memcpy(void *m, void *n); + +/** + * Reads data from a stream and writes it to another stream. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if <code>NULL</code> was + * provided for <code>buf</code>, this is the size of the buffer that shall be + * implicitly created + * @param n the maximum number of bytes that shall be copied + * @return the total number of bytes copied + */ +size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc, + char* buf, size_t bufsize, size_t n); + +/** + * Shorthand for ucx_stream_copy using the default copy buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @return total number of bytes copied + */ +#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, SIZE_MAX) + +/** + * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param n maximum number of bytes that shall be copied + * @return total number of bytes copied + */ +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, n) + /** * Wraps the strcmp function. * @param s1 string one