added memstream to ucx - still little work to do

Tue, 09 Oct 2012 15:02:40 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 09 Oct 2012 15:02:40 +0200
changeset 56
76caac0da4a0
parent 55
180bc6b18fec
child 57
e18157c52985

added memstream to ucx - still little work to do

test/Makefile file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
test/memstream_tests.c file | annotate | diff | comparison | revisions
test/memstream_tests.h file | annotate | diff | comparison | revisions
ucx/Makefile file | annotate | diff | comparison | revisions
ucx/memstream.c file | annotate | diff | comparison | revisions
ucx/memstream.h file | annotate | diff | comparison | revisions
--- a/test/Makefile	Tue Oct 09 10:21:18 2012 +0200
+++ b/test/Makefile	Tue Oct 09 15:02:40 2012 +0200
@@ -35,6 +35,7 @@
 SRC += map_tests.c
 SRC += string_tests.c
 SRC += logging_tests.c
+SRC += memstream_tests.c
 
 OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
 
--- a/test/main.c	Tue Oct 09 10:21:18 2012 +0200
+++ b/test/main.c	Tue Oct 09 15:02:40 2012 +0200
@@ -39,6 +39,7 @@
 #include "string_tests.h"
 #include "mpool_tests.h"
 #include "map_tests.h"
+#include "memstream_tests.h"
 
 int cmp_string(void* o1, void* o2, void* data) {
     return strcmp((char*)o1, (char*)o2);
@@ -162,6 +163,15 @@
         ucx_test_register(suite, test_sstr_len_cat);
         ucx_test_register(suite, test_sstrsplit);
 
+        /* UcxMemstream Tests */
+        ucx_test_register(suite, test_ucx_memseektell);
+        ucx_test_register(suite, test_ucx_memputc);
+        ucx_test_register(suite, test_ucx_memgetc);
+        ucx_test_register(suite, test_ucx_memwrite);
+        ucx_test_register(suite, test_ucx_memread);
+        ucx_test_register(suite, test_ucx_memprintf);
+        ucx_test_register(suite, test_ucx_memscanf);
+
         ucx_test_run(suite, stdout);
         fflush(stdout);
         ucx_test_suite_free(suite);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/memstream_tests.c	Tue Oct 09 15:02:40 2012 +0200
@@ -0,0 +1,231 @@
+/*
+ *
+ */
+
+#include "memstream_tests.h"
+
+UCX_TEST_IMPLEMENT(test_ucx_memseektell) {
+    char *buffer = malloc(16);
+    memset(buffer, 32, 7);
+    buffer[7] = 0;
+
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+    int r;
+
+    UCX_TEST_BEGIN
+
+    r = ucx_memseek(m, 5, SEEK_SET);
+    UCX_TEST_ASSERT(r == 0, "seek SET+5 failed");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 5, "seek SET+5 set wrong position");
+
+    r = ucx_memseek(m, 20, SEEK_SET);
+    UCX_TEST_ASSERT(r != 0, "seek beyond bounds shall fail");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 5,
+            "failed seek shall leave pos unchanged");
+
+    r = ucx_memseek(m, 5, SEEK_CUR);
+    UCX_TEST_ASSERT(r == 0, "seek CUR+5 failed");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 10, "seek CUR+5 set wrong position");
+
+    r = ucx_memseek(m, 10, SEEK_CUR);
+    UCX_TEST_ASSERT(r != 0, "seek CUR beyond bounds shall fail");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 10,
+            "failed seek shall leave pos unchanged");
+
+    r = ucx_memseek(m, -5, SEEK_END);
+    UCX_TEST_ASSERT(r == 0, "seek END-5 failed");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 2, "seek END-5 set wrong position");
+
+    r = ucx_memseek(m, -10, SEEK_END);
+    UCX_TEST_ASSERT(r != 0, "seek END beyond bounds shall fail");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 2,
+            "failed seek shall leave pos unchanged");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memputc) {
+    char *buffer = malloc(16);
+    memset(buffer, 32, 16);
+
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+    int r;
+
+    UCX_TEST_BEGIN
+
+    ucx_memputc(m, 48); ucx_memputc(m, 48); ucx_memputc(m, 48);
+    UCX_TEST_ASSERT(ucx_memtell(m) == 3, "pos wrong after first 3 puts");
+    ucx_memseek(m, 10, SEEK_CUR);
+    ucx_memputc(m, 48); ucx_memputc(m, 48); ucx_memputc(m, 48);
+    UCX_TEST_ASSERT(ucx_memtell(m) == 16, "pos wrong after last 3 puts");
+    UCX_TEST_ASSERT(ucx_memeof(m), "eof not set");
+    UCX_TEST_ASSERT(!ucx_memoverflow(m), "overflow shall not be set");
+    UCX_TEST_ASSERT(ucx_memputc(m, 48) == EOF, "put shall return EOF on memof");
+    UCX_TEST_ASSERT(memcmp(buffer, "000          000", 16) == 0,
+            "buffer contains incorrect content");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memgetc) {
+    char *buffer = malloc(16);
+    memset(buffer, 32, 8);
+    for (int i = 8; i < 16 ; i++) {
+        buffer[i] = 40+i;
+    }
+
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+    int r;
+
+    UCX_TEST_BEGIN
+
+    char rb[16];
+    for (int i = 0 ; i < 16 ; i++) {
+        UCX_TEST_ASSERT(ucx_memtell(m) == i, "pos wrong during read loop");
+        UCX_TEST_ASSERT(!ucx_memeof(m),
+                "EOF shall not be set during read loop");
+        rb[i] = ucx_memgetc(m);
+    }
+    UCX_TEST_ASSERT(ucx_memtell(m) == 16, "pos wrong after read loop");
+    UCX_TEST_ASSERT(ucx_memeof(m), "EOF not set");
+    UCX_TEST_ASSERT(memcmp(rb, "        01234567", 16) == 0,
+            "read data incorrect");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memwrite) {
+    char *buffer = malloc(16);
+    memset(buffer, 32, 8);
+    for (int i = 8; i < 16 ; i++) {
+        buffer[i] = 40+i;
+    }
+
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+    int r;
+
+    UCX_TEST_BEGIN
+
+    char* teststring = "this is way too much";
+    r = ucx_memwrite(teststring, 1, 20, m);
+    UCX_TEST_ASSERT(r == 16, "string not correctly trimed");
+    UCX_TEST_ASSERT(memcmp(buffer, teststring, 16) == 0,
+            "buffer data incorrect");
+    UCX_TEST_ASSERT(ucx_memeof(m), "eof shall be set");
+    UCX_TEST_ASSERT(!ucx_memoverflow(m), "no overflow shall be caused");
+
+    ucx_memseek(m, 8, SEEK_SET);
+    r = ucx_memwrite("not", 1, 3, m);
+    UCX_TEST_ASSERT(r == 3, "three bytes should be replace");
+    UCX_TEST_ASSERT(memcmp(buffer, "this is not too much", 16) == 0,
+            "modified buffer is incorrect");
+
+    char* threebytestring = "  t  h  r  e  e   ";
+    memset(buffer, 49, 16);
+    ucx_memseek(m, 0, SEEK_SET);
+    r = ucx_memwrite(threebytestring, 3, 6, m);
+    UCX_TEST_ASSERT(r == 15, "three byte string not correctly trimed");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 15,
+            "position after write of three byte string incorrect");
+    UCX_TEST_ASSERT(!ucx_memeof(m), "eof shall not be set");
+    UCX_TEST_ASSERT(memcmp(buffer, "  t  h  r  e  e1", 16) == 0,
+                "bufer is incorrect after three byte string has been written");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memread) {
+    char *buffer = malloc(16);
+    memset(buffer, 56, 8);
+    for (int i = 8; i < 16 ; i++) {
+        buffer[i] = 40+i;
+    }
+
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+    int r;
+
+    UCX_TEST_BEGIN
+
+    char rb[16];
+    memset(rb, 32, 16);
+
+    ucx_memseek(m, 8, SEEK_SET);
+    r = ucx_memread(rb, 1, 16, m);
+    UCX_TEST_ASSERT(r == 8, "read did not stop at buffer end");
+    UCX_TEST_ASSERT(memcmp(rb, "01234567        ", 16) == 0,
+            "buffer incorrect after first read");
+    UCX_TEST_ASSERT(ucx_memeof(m), "eof shall be set");
+
+    ucx_memseek(m, 0, SEEK_SET);
+    r = ucx_memread(rb+8, 1, 8, m);
+    UCX_TEST_ASSERT(r == 8, "read did not read the specified amount of bytes");
+    UCX_TEST_ASSERT(memcmp(rb, "0123456788888888", 16) == 0,
+                "buffer incorrect after second read");
+
+    ucx_memseek(m, 0, SEEK_SET);
+    r = ucx_memread(rb, 3, 6, m);
+    UCX_TEST_ASSERT(r == 15,
+            "three byte read did not read the desired amount of bytes");
+    UCX_TEST_ASSERT(memcmp(rb, "8888888801234568", 16) == 0,
+                    "buffer incorrect after three byte read");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memprintf) {
+    char *buffer = malloc(32);
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+
+    UCX_TEST_BEGIN
+    int r = ucx_memprintf(m, "number: %d char: %c", 15, '6');
+    UCX_TEST_ASSERT(r == 18, "incorrect number of bytes written");
+    UCX_TEST_ASSERT(ucx_memoverflow(m), "overflow shall be detected");
+    UCX_TEST_ASSERT(memcmp(buffer, "number: 15 char:", 16) == 0,
+            "incorrect buffer content");
+
+    ucx_memseek(m, 0, SEEK_SET);
+    ucx_memprintf(m, "a: %d - b: %d", 1, 2);
+    UCX_TEST_ASSERT(!ucx_memoverflow(m), "no overflow shall be deteceted");
+    UCX_TEST_ASSERT(memcmp(buffer, "a: 1 - b: 2char:", 16),
+            "incorrect modified buffer content");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 11, "incorrect position");
+
+    UCX_TEST_END
+
+    ucx_memclose(m);
+    free(buffer);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_memscanf) {
+    char *buffer = "string 3.5 1 stuff";
+    UcxMemstream *m = ucx_memopen(buffer, 16);
+
+    char s[6];
+    float f;
+    int d;
+    UCX_TEST_BEGIN
+    int r = ucx_memscanf(m, "%s %f %d", s, &f, &d);
+    UCX_TEST_ASSERT(r == 3, "3 arguments shall be read");
+    UCX_TEST_ASSERT(strncmp(s, "string", 6) == 0, "incorrect string");
+    UCX_TEST_ASSERT(f == 3.5, "incorrect float");
+    UCX_TEST_ASSERT(d == 1, "incorrect integer");
+    UCX_TEST_ASSERT(ucx_memtell(m) == 12, "incorrect position");
+    UCX_TEST_END
+
+    ucx_memclose(m);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/memstream_tests.h	Tue Oct 09 15:02:40 2012 +0200
@@ -0,0 +1,30 @@
+/* 
+ *
+ */
+
+#ifndef MEMSTREAM_TEST_H
+#define	MEMSTREAM_TEST_H
+
+#include "ucx/test.h"
+#include "ucx/memstream.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* assume open and close to be correct */
+
+UCX_TEST_DECLARE(test_ucx_memseektell)
+UCX_TEST_DECLARE(test_ucx_memputc)
+UCX_TEST_DECLARE(test_ucx_memgetc)
+UCX_TEST_DECLARE(test_ucx_memwrite)
+UCX_TEST_DECLARE(test_ucx_memread)
+UCX_TEST_DECLARE(test_ucx_memprintf)
+UCX_TEST_DECLARE(test_ucx_memscanf)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* MEMSTREAM_TEST_H */
+
--- a/ucx/Makefile	Tue Oct 09 10:21:18 2012 +0200
+++ b/ucx/Makefile	Tue Oct 09 15:02:40 2012 +0200
@@ -37,6 +37,7 @@
 SRC += test.c
 SRC += allocator.c
 SRC += logging.c
+SRC += memstream.c
 
 OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/memstream.c	Tue Oct 09 15:02:40 2012 +0200
@@ -0,0 +1,152 @@
+#include "memstream.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _UcxMemstream {
+    void *space;
+    size_t pos;
+    size_t length;
+    _Bool autofree;
+};
+
+UcxMemstream *ucx_memopen(void* space, size_t length) {
+    UcxMemstream *stream = (UcxMemstream*) malloc(sizeof(UcxMemstream));
+    if (stream) {
+        if (!space) {
+            stream->space = malloc(length);
+            if (!stream->space) {
+                free(stream);
+                return NULL;
+            }
+            memset(stream->space, 0, length);
+            stream->autofree = 1;
+        } else {
+            stream->space = space;
+            stream->autofree = 0;
+        }
+        stream->length = length;
+
+        stream->pos = 0;
+    }
+
+    return stream;
+}
+
+void ucx_memclose(UcxMemstream *stream) {
+    if (stream->autofree) {
+        free(stream->space);
+    }
+    free(stream);
+}
+
+int ucx_memseek(UcxMemstream *stream, long offset, int whence) {
+    size_t npos;
+    switch (whence) {
+    case SEEK_SET:
+        npos = 0;
+        break;
+    case SEEK_CUR:
+        npos = stream->pos;
+        break;
+    case SEEK_END:
+        npos = strlen(stream->space);
+        break;
+    }
+
+    npos += offset;
+
+    if (npos < 0 || npos > stream->length) {
+        return -1;
+    } else {
+        stream->pos = npos;
+        return 0;
+    }
+
+}
+
+int ucx_memeof(UcxMemstream *stream) {
+    return stream->pos >= stream->length;
+}
+
+int ucx_memoverflow(UcxMemstream *stream) {
+    return stream->pos > stream->length;
+}
+
+size_t ucx_memtell(UcxMemstream *stream) {
+    return stream->pos;
+}
+
+size_t ucx_memio(void* d, size_t s, size_t n, UcxMemstream *m, _Bool read) {
+    size_t len;
+    if (m->pos + s*n > m->length) {
+        if (ucx_memoverflow(m)) {
+            len = 0;
+        } else {
+            len = m->length - m->pos;
+            if (s > 1) len -= len%s;
+        }
+    } else {
+        len = s*n;
+    }
+
+    if (len == 0) {
+        return 0;
+    }
+
+    if (read) {
+        memcpy(d, m->space+m->pos, len);
+    } else {
+        memcpy(m->space+m->pos, d, len);
+    }
+    m->pos += len;
+
+    return len;
+}
+
+int ucx_memputc(UcxMemstream *stream, int c) {
+    if (ucx_memeof(stream)) {
+        return EOF;
+    } else {
+        c &= 0xFF;
+        ((char*)(stream->space))[stream->pos] = (char) c;
+        stream->pos++;
+        return c;
+    }
+}
+
+int ucx_memgetc(UcxMemstream *stream) {
+    if (ucx_memeof(stream)) {
+        return EOF;
+    } else {
+        int c = ((char*)(stream->space))[stream->pos];
+        stream->pos++;
+        return c;
+    }
+}
+
+int ucx_memprintf(UcxMemstream *stream, const char* format, ...) {
+    va_list v;
+    va_start(v, format);
+    int r = vsprintf(stream->space+stream->pos, format, v);
+    va_end(v);
+
+    stream->pos += r;
+
+    return r;
+}
+
+int ucx_memscanf(UcxMemstream *stream, const char* format, ...) {
+
+    /* TODO: vsscanf returns the number of fields read,
+     * we need the number of bytes */
+
+    va_list v;
+    va_start(v, format);
+    int r = vsscanf(stream->space+stream->pos, format, v);
+    va_end(v);
+
+    stream->pos += r;
+
+    return r;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/memstream.h	Tue Oct 09 15:02:40 2012 +0200
@@ -0,0 +1,70 @@
+#ifndef MEMSTREAM_H
+#define	MEMSTREAM_H
+
+#include <stdio.h>
+
+/* as fmemopen is a C extension we provide our cross plattform stuff here */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+
+/* as FILE is opaque, we don't do evil hacks but provide an alternative */
+struct _UcxMemstream; /* cauz we are mad about it, we make it opaque, too */
+typedef struct _UcxMemstream UcxMemstream;
+
+UcxMemstream *ucx_memopen(void *space, size_t length);
+void ucx_memclose(UcxMemstream* stream);
+
+/*
+ * Moves the position of the stream to a new position relative to whence.
+ *
+ * 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_memseek 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 stream
+ * remains unchanged.
+ *
+ */
+int ucx_memseek(UcxMemstream *stream, long offset, int whence);
+size_t ucx_memtell(UcxMemstream *stream);
+
+/*
+ * returns non-zero, iff the current stream position has exceeded the last
+ * available byte of the underlying buffer
+ *
+ */
+int ucx_memeof(UcxMemstream *stream);
+/*
+ * returns non-zero, iff the current stream position has exceeded the length
+ * of the underlying buffer
+ *
+ * in contrast to ucx_memeof this function will return zero, if the current
+ * position exactly matches the buffer length
+ *
+ * this function should be called after any ucx_memprintf/ucx_memscanf call
+ */
+int ucx_memoverflow(UcxMemstream *stream);
+
+/* memwrite, memread, memputc and memreadc shall not generate overflows */
+size_t ucx_memio(void *d, size_t s, size_t n, UcxMemstream* m, _Bool read);
+#define ucx_memwrite(data, itemsize, nitems, memstream) \
+    ucx_memio(data, itemsize, nitems, memstream, 0)
+#define ucx_memread(data, itemsize, nitems, memstream) \
+        ucx_memio(data, itemsize, nitems, memstream, 1)
+int ucx_memputc(UcxMemstream *stream, int c);
+int ucx_memgetc(UcxMemstream *stream);
+
+/* printf / scanf may generate overflows */
+int ucx_memprintf(UcxMemstream *stream, const char* format, ...);
+int ucx_memscanf(UcxMemstream *stream, const char* format, ...);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* MEMSTREAM_H */
+

mercurial