completed documentation + changed API for buffer/stream generic copy functions

Tue, 13 Aug 2013 14:20:12 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 13 Aug 2013 14:20:12 +0200
changeset 140
15f871f50bfd
parent 139
dddb9348ea42
child 141
c466e2a6cbd0
child 142
ee8cb27d8b8e

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

mercurial