added printf functions

Wed, 14 Aug 2013 15:22:35 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 14 Aug 2013 15:22:35 +0200
changeset 142
ee8cb27d8b8e
parent 140
15f871f50bfd
child 143
b843d463ac58

added printf functions

test/Makefile file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
test/utils_tests.c file | annotate | diff | comparison | revisions
test/utils_tests.h file | annotate | diff | comparison | revisions
ucx/utils.c file | annotate | diff | comparison | revisions
ucx/utils.h file | annotate | diff | comparison | revisions
--- a/test/Makefile	Tue Aug 13 14:20:12 2013 +0200
+++ b/test/Makefile	Wed Aug 14 15:22:35 2013 +0200
@@ -36,6 +36,7 @@
 SRC += string_tests.c
 SRC += logging_tests.c
 SRC += buffer_tests.c
+SRC += utils_tests.c
 
 OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT))
 
--- a/test/main.c	Tue Aug 13 14:20:12 2013 +0200
+++ b/test/main.c	Wed Aug 14 15:22:35 2013 +0200
@@ -40,6 +40,7 @@
 #include "map_tests.h"
 #include "prop_tests.h"
 #include "buffer_tests.h"
+#include "utils_tests.h"
 
 UCX_EXTERN UCX_TEST(testTestSuitePositive) {
     UCX_TEST_BEGIN
@@ -177,6 +178,10 @@
         ucx_test_register(suite, test_ucx_buffer_read);
         ucx_test_register(suite, test_ucx_buffer_extract);
         ucx_test_register(suite, test_ucx_stream_copy);
+        
+        /* Utils Tests*/
+        ucx_test_register(suite, test_ucx_fprintf);
+        ucx_test_register(suite, test_ucx_asprintf);
 
         ucx_test_run(suite, stdout);
         fflush(stdout);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/utils_tests.c	Wed Aug 14 15:22:35 2013 +0200
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils_tests.h"
+#include "ucx/buffer.h"
+
+UCX_TEST(test_ucx_fprintf) {
+    UcxBuffer *b1 = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND);
+    UcxBuffer *b2 = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
+    
+    char *teststr1 = (char*)calloc(1, 1024);
+    char *teststr2 = (char*)calloc(1, 1024);
+    memset(teststr1, 'a', 1023);
+    memset(teststr2, 'b', 1023);
+    
+    UCX_TEST_BEGIN
+    
+    ucx_fprintf(b1, (write_func)ucx_buffer_write, "Hello %s", "World");
+    UCX_TEST_ASSERT(!strcmp(b1->space, "Hello World"), "wrong content in b1");
+    ucx_fprintf(b1, (write_func)ucx_buffer_write, "\nend.\n");
+    UCX_TEST_ASSERT(!strcmp(b1->space, "Hello World\nend.\n"),
+            "wrong content in b1 after second fprintf");
+    
+    ucx_fprintf(b2, (write_func)ucx_buffer_write, "%s%s", teststr1, teststr2);
+    UCX_TEST_ASSERT(!memcmp(b2->space, teststr1, 1023),
+            "wrong first half in b2");
+    UCX_TEST_ASSERT(!memcmp(b2->space+1023, teststr2, 1023),
+            "wrong second half in b2");
+    
+    UCX_TEST_END
+}
+
+UCX_TEST(test_ucx_asprintf) {
+    char *teststr1 = (char*)calloc(1, 1024);
+    char *teststr2 = (char*)calloc(1, 1024);
+    memset(teststr1, 'a', 1023);
+    memset(teststr2, 'b', 1023);
+    UcxAllocator *a = ucx_default_allocator();
+    
+    UCX_TEST_BEGIN
+    
+    sstr_t s1 = ucx_asprintf(a, "int: %d\nHello %s!", 123, "World");
+    UCX_TEST_ASSERT(s1.ptr, "s1.ptr is NULL");
+    UCX_TEST_ASSERT(s1.length == 21, "wrong length");
+    UCX_TEST_ASSERT(!sstrcmp(s1, S("int: 123\nHello World!")), "wrong content");
+    free(s1.ptr);
+    
+    sstr_t s2 = ucx_asprintf(a, "%s%s", teststr1, teststr2);
+    UCX_TEST_ASSERT(!memcmp(s2.ptr, teststr1, 1023),
+            "wrong first half in s2");
+    UCX_TEST_ASSERT(!memcmp(s2.ptr+1023, teststr2, 1023),
+            "wrong second half in s2");
+    
+    UCX_TEST_END
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/utils_tests.h	Wed Aug 14 15:22:35 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UTILS_TESTS_H
+#define	UTILS_TESTS_H
+
+#include "ucx/test.h"
+#include "ucx/utils.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+UCX_TEST(test_ucx_fprintf);
+UCX_TEST(test_ucx_asprintf);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* UTILS_TESTS_H */
+
--- a/ucx/utils.c	Tue Aug 13 14:20:12 2013 +0200
+++ b/ucx/utils.c	Wed Aug 14 15:22:35 2013 +0200
@@ -28,6 +28,9 @@
 
 #include "utils.h"
 #include <math.h>
+#include <stdio.h>
+#include <limits.h>
+#include <errno.h>
 
 /* COPY FUCNTIONS */
 void* ucx_strcpy(void* s, void* data) {
@@ -75,7 +78,7 @@
     return ncp;
 }
 
-/* COMPARE FUNCTION */
+/* COMPARE FUNCTIONS */
 
 int ucx_strcmp(void *s1, void *s2, void *data) {
     return strcmp((char*)s1, (char*)s2);
@@ -128,3 +131,80 @@
 int ucx_memcmp(void *ptr1, void *ptr2, void *n) {
     return memcmp(ptr1, ptr2, *((size_t*)n));
 }
+
+/* PRINTF FUNCTIONS */
+
+#define UCX_PRINTF_BUFSIZE 256
+
+int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) {
+    va_list ap;
+    int ret;
+    va_start(ap, fmt);
+    ret = ucx_vfprintf(stream, wfc, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) {
+    char buf[UCX_PRINTF_BUFSIZE];
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret < 0) {
+        return ret;
+    } else if (ret < UCX_PRINTF_BUFSIZE) {
+        return (int)wfc(buf, 1, ret, stream);
+    } else {
+        if (ret == INT_MAX) {
+            errno = ENOMEM;
+            return -1;
+        }
+        
+        int len = ret + 1;
+        char *newbuf = (char*)malloc(len);
+        if (!newbuf) {
+            return -1;
+        }
+        
+        ret = vsnprintf(newbuf, len, fmt, ap);
+        if (ret > 0) {
+            ret = (int)wfc(newbuf, 1, ret, stream);
+        }
+        free(newbuf);
+    }
+    return ret;
+}
+
+sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) {
+    va_list ap;
+    sstr_t ret;
+    va_start(ap, fmt);
+    ret = ucx_vasprintf(allocator, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) {
+    sstr_t s;
+    s.ptr = NULL;
+    s.length = 0;
+    char buf[UCX_PRINTF_BUFSIZE];
+    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
+    if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
+        s.ptr = (char*)a->malloc(a->pool, ret + 1);
+        s.length = (size_t)ret;
+        memcpy(s.ptr, buf, ret);
+        s.ptr[s.length] = '\0';
+    } else if (ret == INT_MAX) {
+        errno = ENOMEM;
+    } else  {
+        int len = ret + 1;
+        s.ptr = (char*)a->malloc(a->pool, len);
+        ret = vsnprintf(s.ptr, len, fmt, ap);
+        if (ret < 0) {
+            free(s.ptr);
+            s.ptr = NULL;
+        } else {
+            s.length = (size_t)ret;
+        }
+    }
+    return s;
+}
--- a/ucx/utils.h	Tue Aug 13 14:20:12 2013 +0200
+++ b/ucx/utils.h	Wed Aug 14 15:22:35 2013 +0200
@@ -43,8 +43,11 @@
 #endif
 
 #include "ucx.h"
+#include "string.h"
+#include "allocator.h"
 #include <stdint.h>
 #include <string.h>
+#include <stdarg.h>
 
 /**
  * Copies a string.
@@ -133,7 +136,6 @@
  * @return -1, if *i1 is less than *i2, 0 if both are equal,
  * 1 if *i1 is greater than *i2
  */
-
 int ucx_intcmp(void *i1, void *i2, void *data);
 
 /**
@@ -155,7 +157,6 @@
  * @return -1, if *d1 is less than *d2, 0 if both are equal,
  * 1 if *d1 is greater than *d2
  */
-
 int ucx_doublecmp(void *d1, void *d2, void *data);
 
 /**
@@ -177,6 +178,57 @@
  */
 int ucx_memcmp(void *ptr1, void *ptr2, void *n);
 
+/**
+ * A printf like function which writes the output to a stream using a write
+ * function.
+ * @param stream the stream where to write the data
+ * @param wfc the write function for the stream
+ * @param fmt format string
+ * @param ... additional arguments
+ * @return the total number of bytes written
+ */
+int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...);
+
+/**
+ * Same as ucx_fprintf() but with an argument list instead of variadic
+ * arguments.
+ * @param stream the stream where to write the data
+ * @param wfc the write function for the stream
+ * @param fmt format string
+ * @param ap argument list
+ * @return the total number of bytes written
+ * @see ucx_fprintf()
+ */
+int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap);
+
+/**
+ * A printf lile function which stores the result in a newly created string.
+ * 
+ * The sstr_t data is allocated with the allocators ucx_allocator_malloc
+ * function. So it is implementation depended, whether the returned
+ * sstr_t.ptr pointer must be passed to the allocators ucx_allocator_free
+ * function manually.
+ * 
+ * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
+ * terminated.
+ * 
+ * @param allocator a valid instance of an UcxAllocator
+ * @param fmt format string
+ * @param ... additional arguments
+ * @return a new string
+ */
+sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...);
+
+/**
+ * Same as ucx_asprintf() but with an argument list instead of variadic
+ * arguments.
+ * @param allocator a valid instance of an UcxAllocator
+ * @param fmt format string
+ * @param ap argument list
+ * @return a new string
+ */
+sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap);
+
 #ifdef	__cplusplus
 }
 #endif

mercurial