new properties parser

Fri, 12 Jul 2013 20:50:18 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 12 Jul 2013 20:50:18 +0200
changeset 108
d2b1e67b2b48
parent 107
86b19c98b5fd
child 109
75cb6590358b

new properties parser

g++-debug.mk file | annotate | diff | comparison | revisions
gcc-debug.mk file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/main.c file | annotate | diff | comparison | revisions
test/prop_tests.c file | annotate | diff | comparison | revisions
test/prop_tests.h file | annotate | diff | comparison | revisions
ucx/Makefile file | annotate | diff | comparison | revisions
ucx/map.c file | annotate | diff | comparison | revisions
ucx/properties.c file | annotate | diff | comparison | revisions
ucx/properties.h file | annotate | diff | comparison | revisions
ucx/string.c file | annotate | diff | comparison | revisions
ucx/string.h file | annotate | diff | comparison | revisions
--- a/g++-debug.mk	Thu Jul 11 17:32:48 2013 +0200
+++ b/g++-debug.mk	Fri Jul 12 20:50:18 2013 +0200
@@ -31,7 +31,7 @@
 AR = ar
 RM = rm
 
-CFLAGS  = -std=gnu++0x -g -O2 -fstrict-aliasing -Wall -pedantic -c
+CFLAGS  = -std=gnu++0x -g -fstrict-aliasing -Wall -pedantic -c
 COFLAGS = -o
 LDFLAGS = 
 LOFLAGS = -o
--- a/gcc-debug.mk	Thu Jul 11 17:32:48 2013 +0200
+++ b/gcc-debug.mk	Fri Jul 12 20:50:18 2013 +0200
@@ -31,7 +31,7 @@
 AR = ar
 RM = rm
 
-CFLAGS  = -std=gnu99 -g -O2 -fstrict-aliasing -Wall -pedantic -c
+CFLAGS  = -std=gnu99 -g -fstrict-aliasing -Wall -pedantic -c
 COFLAGS = -o
 LDFLAGS = 
 LOFLAGS = -o
--- a/test/Makefile	Thu Jul 11 17:32:48 2013 +0200
+++ b/test/Makefile	Fri Jul 12 20:50:18 2013 +0200
@@ -33,6 +33,7 @@
 SRC += dlist_tests.c
 SRC += mpool_tests.c
 SRC += map_tests.c
+SRC += prop_tests.c
 SRC += string_tests.c
 SRC += logging_tests.c
 SRC += buffer_tests.c
--- a/test/main.c	Thu Jul 11 17:32:48 2013 +0200
+++ b/test/main.c	Fri Jul 12 20:50:18 2013 +0200
@@ -39,6 +39,7 @@
 #include "string_tests.h"
 #include "mpool_tests.h"
 #include "map_tests.h"
+#include "prop_tests.h"
 #include "buffer_tests.h"
 
 UCX_TEST_IMPLEMENT(testTestSuitePositive) {
@@ -168,8 +169,15 @@
         ucx_test_register(suite, test_ucx_map_store_load_with_mempool);
         ucx_test_register(suite, test_ucx_map_clone);
         ucx_test_register(suite, test_ucx_map_rehash);
-
-        /* UcxMemstream Tests */
+        
+        /* UcxPropertiesParser Tests */
+        ucx_test_register(suite, test_ucx_prop_new);
+        ucx_test_register(suite, test_ucx_prop_parse);
+        ucx_test_register(suite, test_ucx_prop_parse_multi);
+        ucx_test_register(suite, test_ucx_prop_parse_part);
+        ucx_test_register(suite, test_ucx_prop_parse_long);
+        
+        /* UcxBuffer Tests */
         ucx_test_register(suite, test_ucx_buffer_seektell);
         ucx_test_register(suite, test_ucx_buffer_putc);
         ucx_test_register(suite, test_ucx_buffer_putc_ax);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/prop_tests.c	Fri Jul 12 20:50:18 2013 +0200
@@ -0,0 +1,362 @@
+/*
+ * 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 "prop_tests.h"
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_new) {
+    UcxPropParser *parser = ucx_prop_new();
+    
+    UCX_TEST_BEGIN
+            
+    UCX_TEST_ASSERT(parser != NULL, "failed");
+    UCX_TEST_ASSERT(parser->buffer == NULL, "parser has buffer");
+    UCX_TEST_ASSERT(parser->tmp == NULL, "parser has tmp buffer");
+    
+    UCX_TEST_END
+            
+    ucx_prop_free(parser);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_parse) {  
+    char *tests[] = {
+        "name = value\n",
+        "name=value\n",
+        "n=value\n",
+        "name=v\n",
+        "n=v\n",
+        "name = value # comment\n",
+        "#comment\nn=v\n",
+        "# comment1\n# comment2\n\n    \n\nname = value\n",
+        "    name     =      value\n",
+        "name = value\n\n"
+    };
+    
+    char *names[] = {
+        "name",
+        "name",
+        "n",
+        "name",
+        "n",
+        "name",
+        "n",
+        "name",
+        "name",
+        "name"
+    };
+    
+    char *values[] = {
+        "value",
+        "value",
+        "value",
+        "v",
+        "v",
+        "value",
+        "v",
+        "value",
+        "value",
+        "value"
+    };
+    
+    UCX_TEST_BEGIN
+    
+    sstr_t name;
+    sstr_t value;
+    
+    for(int i=0;i<10;i++) {
+        UcxPropParser *parser = ucx_prop_new();
+        
+        ucx_prop_fill(parser, tests[i], strlen(tests[i]));
+        UCX_TEST_ASSERT(parser->buffer == tests[i], "fill failed");
+        UCX_TEST_ASSERT(parser->buflen == strlen(tests[i]), "wrong buflen");
+        
+        int r = ucx_prop_parse(parser, &name, &value);
+        sstr_t n = sstr(names[i]);
+        sstr_t v = sstr(values[i]);
+        UCX_TEST_ASSERT(r == 1, "parse returned 0");
+        UCX_TEST_ASSERT((!sstrcmp(name, n)), "wrong property name");
+        UCX_TEST_ASSERT((!sstrcmp(value, v)), "wrong property value");
+        
+        r = ucx_prop_parse(parser, &name, &value);
+        UCX_TEST_ASSERT(r == 0, "parse returned 1");
+        UCX_TEST_ASSERT(parser->tmp == NULL, "tmp not NULL");
+        UCX_TEST_ASSERT(parser->tmpcap == 0, "tmpcap not NULL");
+        UCX_TEST_ASSERT(parser->tmplen == 0, "tmplen not NULL");
+        
+        ucx_prop_free(parser);
+    }
+    
+    UCX_TEST_END       
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_parse_multi) {
+    char *names[] = {
+        "a",
+        "b",
+        "c",
+        "uap",
+        "name",
+        "key1",
+        "key2",
+        "key3"
+    };
+    
+    char *values[] = {
+        "a value",
+        "b value",
+        "core",
+        "core",
+        "ucx",
+        "value1",
+        "value2",
+        "value3"
+    };
+    
+    char *str = "#\n"
+        "# properties\n"
+        "# contains key/value pairs\n"
+        "#\n"
+        "a = a value\n"
+        "b = b value\n"
+        "c = core\n"
+        "\n# test\n"
+        "uap = core\n"
+        "name = ucx\n"
+        "# no = property\n"
+        "key1 = value1\n"
+        "#key1 = wrong value\n"
+        "#key2 = not value 2\n"
+        "key2 = value2\n"
+        "\n\n\n        \n           key3=value3\n";
+    
+    UcxPropParser *parser = ucx_prop_new();
+    
+    UCX_TEST_BEGIN
+    
+    ucx_prop_fill(parser, str, strlen(str));
+    
+    sstr_t name;
+    sstr_t value;
+    for(int i=0;i<8;i++) {
+        int r = ucx_prop_parse(parser, &name, &value);
+        UCX_TEST_ASSERT(r == 1, "parse returned 0");
+        UCX_TEST_ASSERT((!sstrcmp(name, sstr(names[i]))), "wrong name");
+        UCX_TEST_ASSERT((!sstrcmp(value, sstr(values[i]))), "wrong value");
+    }
+    int r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    UCX_TEST_END
+    
+    ucx_prop_free(parser);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_parse_part) {
+    UcxPropParser *parser = ucx_prop_new();
+    char *str;
+    int r;
+    sstr_t name;
+    sstr_t value;
+    
+    UCX_TEST_BEGIN
+    
+    str = "";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "  \n";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "name";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "    ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "= ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "value";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "\n";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("name"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
+    
+    // second round
+    str = "#comment\n";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "#comment\nname = ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "value\na = b\n";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("name"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
+    
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("a"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr("b"))), "wrong value");
+    
+    str = "# comment\n#\n#\ntests = ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "test1 ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "test2 test3 test4\n";
+    sstr_t testv = sstr("test1 test2 test3 test4");
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("tests"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, testv)), "wrong value");
+    
+    // test if parse finds a name/value after a tmp comment
+    str = "# just a comment";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = " in 3";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = " parts\na = 1\n";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("a"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr("1"))), "wrong value");
+    
+    UCX_TEST_END
+    
+    ucx_prop_free(parser);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_parse_long) {
+    UcxPropParser *parser = ucx_prop_new();
+    int r;
+    size_t name_len = 512;
+    char *long_name = (char*)malloc(name_len);
+    memset(long_name, 'a', 70);
+    memset(long_name+70, 'b', 242);
+    memset(long_name+312, 'c', 200);
+    
+    size_t value_len = 2048;
+    char *long_value = (char*)malloc(value_len);
+    memset(long_value, 'x', 1024);
+    memset(long_value+1024, 'y', 1024);
+    
+    UCX_TEST_BEGIN
+    
+    sstr_t name;
+    sstr_t value;
+    
+    ucx_prop_fill(parser, long_name, 10);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_name+10, 202);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_name+212, 200);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_name+412, 100);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    char *str = " = ";
+    ucx_prop_fill(parser, str, strlen(str));
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_value, 512);
+    r = ucx_prop_parse(parser, &name, &value); 
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_value+512, 1024);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    ucx_prop_fill(parser, long_value+1536, 512);
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    str = "\n#comment\nkey = value\n";
+    ucx_prop_fill(parser, str, strlen(str));    
+    r = ucx_prop_parse(parser, &name, &value);
+    sstr_t n = sstrn(long_name, name_len);
+    sstr_t v = sstrn(long_value, value_len);
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, n)), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, v)), "wrong value");
+    
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 1, "parse returned 0");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr("key"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
+    
+    r = ucx_prop_parse(parser, &name, &value);
+    UCX_TEST_ASSERT(r == 0, "parse returned 1");
+    
+    UCX_TEST_END
+    
+    free(long_name);
+    free(long_value);
+    ucx_prop_free(parser);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/prop_tests.h	Fri Jul 12 20:50:18 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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 PROP_TESTS_H
+#define	PROP_TESTS_H
+
+#include "ucx/test.h"
+#include "ucx/properties.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+UCX_TEST_DECLARE(test_ucx_prop_new);
+UCX_TEST_DECLARE(test_ucx_prop_parse);
+UCX_TEST_DECLARE(test_ucx_prop_parse_multi);
+UCX_TEST_DECLARE(test_ucx_prop_parse_part);
+UCX_TEST_DECLARE(test_ucx_prop_parse_long);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* PROP_TESTS_H */
+
--- a/ucx/Makefile	Thu Jul 11 17:32:48 2013 +0200
+++ b/ucx/Makefile	Fri Jul 12 20:50:18 2013 +0200
@@ -33,6 +33,7 @@
 SRC += list.c 
 SRC += dlist.c
 SRC += map.c
+SRC += properties.c
 SRC += mempool.c
 SRC += string.c
 SRC += test.c
--- a/ucx/map.c	Thu Jul 11 17:32:48 2013 +0200
+++ b/ucx/map.c	Fri Jul 12 20:50:18 2013 +0200
@@ -39,7 +39,7 @@
     if(size == 0) {
         size = 16;
     }
-    
+       
     if(!allocator) {
         allocator = ucx_default_allocator();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/properties.c	Fri Jul 12 20:50:18 2013 +0200
@@ -0,0 +1,204 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "properties.h"
+
+UcxPropParser *ucx_prop_new() {
+    UcxPropParser *parser = (UcxPropParser*)malloc(
+            sizeof(UcxPropParser));
+    if(!parser) {
+        return NULL;
+    }
+    
+    parser->buffer = NULL;
+    parser->buflen = 0;
+    parser->pos = 0;
+    parser->tmp = NULL;
+    parser->tmplen = 0;
+    parser->tmpcap = 0;
+    parser->delimiter = '=';
+    parser->comment1 = '#';
+    parser->comment2 = 0;
+    parser->comment3 = 0;   
+    
+    return parser;
+}
+
+void ucx_prop_free(UcxPropParser *parser) {
+    if(parser->tmp) {
+        free(parser->tmp);
+    }
+    free(parser);
+}
+
+void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len) {
+    parser->buffer = buf;
+    parser->buflen = len;
+    parser->pos = 0;
+}
+
+static void parser_tmp_append(UcxPropParser *parser, char *buf, size_t len) {
+    if(parser->tmpcap - parser->tmplen < len) {
+        size_t newcap = parser->tmpcap + len + 64;
+        parser->tmp = (char*)realloc(parser->tmp, newcap);
+        parser->tmpcap = newcap;
+    }
+    memcpy(parser->tmp + parser->tmplen, buf, len);
+    parser->tmplen += len;
+}
+
+int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value)  {   
+    if(parser->tmplen > 0) {
+        char *buf = parser->buffer + parser->pos;
+        size_t len = parser->buflen - parser->pos;
+        sstr_t str = sstrn(buf, len);
+        sstr_t nl = sstrchr(str, '\n');
+        if(nl.ptr) {
+            size_t newlen = (size_t)(nl.ptr - buf) + 1;
+            parser_tmp_append(parser, buf, newlen);
+            // the tmp buffer contains exactly one line now
+            
+            char *orig_buf = parser->buffer;
+            size_t orig_len = parser->buflen;
+            
+            parser->buffer = parser->tmp;
+            parser->buflen = parser->tmplen;
+            parser->pos = 0;    
+            parser->tmp = NULL;
+            parser->tmpcap = 0;
+            parser->tmplen = 0;
+            // run parse with the tmp buffer as main buffer
+            int ret = ucx_prop_parse(parser, name, value);
+            
+            // restore original buffer
+            parser->tmp = parser->buffer;
+            parser->buffer = orig_buf;
+            parser->buflen = orig_len;
+            parser->pos = newlen;
+            
+            /*
+             * if ret == 0 the tmp buffer contained just space or comment
+             * we parse again with the original buffer to get a name/value
+             * or a new tmp buffer
+             */
+            return ret ? ret : ucx_prop_parse(parser, name, value);
+        } else {
+            parser_tmp_append(parser, buf, len);
+            return 0;
+        }
+    } else if(parser->tmp) {
+        free(parser->tmp);
+        parser->tmp = NULL;
+    }
+    
+    char comment1 = parser->comment1;
+    char comment2 = parser->comment2;
+    char comment3 = parser->comment3;
+    char delimiter = parser->delimiter;
+    
+    // get one line and parse it
+    while(1) {
+        if(parser->pos >= parser->buflen) {
+            return 0;
+        }
+        char *buf = parser->buffer + parser->pos;
+        size_t len = parser->buflen - parser->pos;
+        
+        /*
+         * First we check if we have at least one line. We also get indices of
+         * delimiter and comment chars
+         */
+        size_t delimiter_index = 0;
+        size_t comment_index = 0;
+        int has_comment = 0;
+
+        size_t i = 0;
+        char c = 0;
+        for(;i<len;i++) {
+            c = buf[i];
+            if(c == comment1 || c == comment2 || c == comment3) {
+                if(comment_index == 0) {
+                    comment_index = i;
+                    has_comment = 1;
+                }
+            } else if(c == delimiter) {
+                if(delimiter_index == 0 && !has_comment) {
+                    delimiter_index = i;
+                }
+            } else if(c == '\n') {
+                break;
+            }
+        }
+
+        if(c != '\n') {
+            // we have not enough data for a line
+            // store remaining bytes in temporary buffer for next round
+            parser->tmpcap = len + 128;
+            parser->tmp = (char*)malloc(parser->tmpcap);
+            parser->tmplen = len;
+            memcpy(parser->tmp, buf, len);
+            return 0;
+        }
+        
+        sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
+        // check line
+        if(delimiter_index == 0) {
+            line = sstrtrim(line);
+            if(line.length != 0) {
+                // syntax error
+                // TODO
+            }
+            parser->pos += i + 1;
+            continue;
+        }
+        
+        sstr_t n = sstrn(buf, delimiter_index);
+        sstr_t v = sstrn(buf + delimiter_index + 1, i - delimiter_index - 1); 
+        n = sstrtrim(n);
+        v = sstrtrim(v);      
+        if(n.length == 0 || v.length == 0) {
+            // syntax error
+            // TODO
+            parser->pos += i + 1;
+            continue;
+        }
+        
+        *name = n;
+        *value = v;
+        
+        parser->pos += i + 1;
+        break;
+    }
+    
+    return 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ucx/properties.h	Fri Jul 12 20:50:18 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * 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 PROPERTIES_H
+#define	PROPERTIES_H
+
+#include "ucx.h"
+#include "map.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    char   *buffer;
+    size_t buflen;
+    size_t pos;
+    char   *tmp;
+    size_t tmplen;
+    size_t tmpcap;
+    char   delimiter;
+    char   comment1;
+    char   comment2;
+    char   comment3;
+} UcxPropParser;
+
+
+UcxPropParser *ucx_prop_new();
+void ucx_prop_free(UcxPropParser *parser);
+void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len);
+int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* PROPERTIES_H */
+
--- a/ucx/string.c	Thu Jul 11 17:32:48 2013 +0200
+++ b/ucx/string.c	Fri Jul 12 20:50:18 2013 +0200
@@ -106,6 +106,18 @@
     return new_sstr;
 }
 
+sstr_t sstrchr(sstr_t s, int c) {
+    for(size_t i=0;i<s.length;i++) {
+        if(s.ptr[i] == c) {
+            return sstrsubs(s, i);
+        }
+    }
+    sstr_t n;
+    n.ptr = NULL;
+    n.length = 0;
+    return n;
+}
+
 sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
     if (d.length == 0) {
         return NULL;
--- a/ucx/string.h	Thu Jul 11 17:32:48 2013 +0200
+++ b/ucx/string.h	Fri Jul 12 20:50:18 2013 +0200
@@ -92,6 +92,11 @@
 sstr_t sstrsubsl(sstr_t s, size_t start, size_t length);
 
 /*
+ * 
+ */
+sstr_t sstrchr(sstr_t s, int c);
+
+/*
  * splits s into n parts
  *
  * s    the string to split

mercurial