added properties load/store functions

Sun, 14 Jul 2013 17:11:34 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 14 Jul 2013 17:11:34 +0200
changeset 109
75cb6590358b
parent 108
d2b1e67b2b48
child 110
1cf71e56f01e

added properties load/store functions

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/map.h 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/test/main.c	Fri Jul 12 20:50:18 2013 +0200
+++ b/test/main.c	Sun Jul 14 17:11:34 2013 +0200
@@ -176,6 +176,9 @@
         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);
+        ucx_test_register(suite, test_ucx_prop_parse2map);
+        ucx_test_register(suite, test_ucx_properties_load);
+        ucx_test_register(suite, test_ucx_properties_store);
         
         /* UcxBuffer Tests */
         ucx_test_register(suite, test_ucx_buffer_seektell);
--- a/test/prop_tests.c	Fri Jul 12 20:50:18 2013 +0200
+++ b/test/prop_tests.c	Sun Jul 14 17:11:34 2013 +0200
@@ -43,7 +43,7 @@
 }
 
 UCX_TEST_IMPLEMENT(test_ucx_prop_parse) {  
-    char *tests[] = {
+    const char *tests[] = {
         "name = value\n",
         "name=value\n",
         "n=value\n",
@@ -56,7 +56,7 @@
         "name = value\n\n"
     };
     
-    char *names[] = {
+    const char *names[] = {
         "name",
         "name",
         "n",
@@ -69,7 +69,7 @@
         "name"
     };
     
-    char *values[] = {
+    const char *values[] = {
         "value",
         "value",
         "value",
@@ -90,13 +90,13 @@
     for(int i=0;i<10;i++) {
         UcxPropParser *parser = ucx_prop_new();
         
-        ucx_prop_fill(parser, tests[i], strlen(tests[i]));
+        ucx_prop_fill(parser, (char*)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]);
+        sstr_t n = sstr((char*)names[i]);
+        sstr_t v = sstr((char*)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");
@@ -114,7 +114,7 @@
 }
 
 UCX_TEST_IMPLEMENT(test_ucx_prop_parse_multi) {
-    char *names[] = {
+    const char *names[] = {
         "a",
         "b",
         "c",
@@ -125,7 +125,7 @@
         "key3"
     };
     
-    char *values[] = {
+    const char *values[] = {
         "a value",
         "b value",
         "core",
@@ -136,7 +136,7 @@
         "value3"
     };
     
-    char *str = "#\n"
+    const char *str = "#\n"
         "# properties\n"
         "# contains key/value pairs\n"
         "#\n"
@@ -157,15 +157,16 @@
     
     UCX_TEST_BEGIN
     
-    ucx_prop_fill(parser, str, strlen(str));
+    ucx_prop_fill(parser, (char*)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");
+        UCX_TEST_ASSERT((!sstrcmp(name, sstr((char*)names[i]))), "wrong name");
+        UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)values[i]))),
+                "wrong value");
     }
     int r = ucx_prop_parse(parser, &name, &value);
     UCX_TEST_ASSERT(r == 0, "parse returned 1");
@@ -177,7 +178,7 @@
 
 UCX_TEST_IMPLEMENT(test_ucx_prop_parse_part) {
     UcxPropParser *parser = ucx_prop_new();
-    char *str;
+    const char *str;
     int r;
     sstr_t name;
     sstr_t value;
@@ -185,100 +186,100 @@
     UCX_TEST_BEGIN
     
     str = "";
-    ucx_prop_fill(parser, str, strlen(str));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr((char*)"name"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)"value"))), "wrong value");
     
     // second round
     str = "#comment\n";
-    ucx_prop_fill(parser, str, strlen(str));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr((char*)"name"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)"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");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr((char*)"a"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)"b"))), "wrong value");
     
     str = "# comment\n#\n#\ntests = ";
-    ucx_prop_fill(parser, str, strlen(str));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    sstr_t testv = sstr((char*)"test1 test2 test3 test4");
+    ucx_prop_fill(parser, (char*)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(name, sstr((char*)"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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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));
+    ucx_prop_fill(parser, (char*)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_ASSERT((!sstrcmp(name, sstr((char*)"a"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)"1"))), "wrong value");
     
     UCX_TEST_END
     
@@ -320,8 +321,8 @@
     r = ucx_prop_parse(parser, &name, &value);
     UCX_TEST_ASSERT(r == 0, "parse returned 1");
     
-    char *str = " = ";
-    ucx_prop_fill(parser, str, strlen(str));
+    const char *str = " = ";
+    ucx_prop_fill(parser, (char*)str, strlen(str));
     r = ucx_prop_parse(parser, &name, &value);
     UCX_TEST_ASSERT(r == 0, "parse returned 1");
     
@@ -338,7 +339,7 @@
     UCX_TEST_ASSERT(r == 0, "parse returned 1");
     
     str = "\n#comment\nkey = value\n";
-    ucx_prop_fill(parser, str, strlen(str));    
+    ucx_prop_fill(parser, (char*)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);
@@ -348,8 +349,8 @@
     
     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");
+    UCX_TEST_ASSERT((!sstrcmp(name, sstr((char*)"key"))), "wrong name");
+    UCX_TEST_ASSERT((!sstrcmp(value, sstr((char*)"value"))), "wrong value");
     
     r = ucx_prop_parse(parser, &name, &value);
     UCX_TEST_ASSERT(r == 0, "parse returned 1");
@@ -360,3 +361,182 @@
     free(long_value);
     ucx_prop_free(parser);
 }
+
+UCX_TEST_IMPLEMENT(test_ucx_prop_parse2map) {
+    UcxMap *map = ucx_map_new(16);
+    UcxPropParser *parser = ucx_prop_new();
+    
+    UCX_TEST_BEGIN
+    
+    const char *str = "key1 = value1\nkey2 = value2\n\n#comment\n\nkey3 = value3\n";
+    ucx_prop_fill(parser, (char*)str, strlen(str));
+    
+    int r = ucx_prop_parse2map(parser, map);
+    
+    UCX_TEST_ASSERT(r == 0, "parse2map failed");
+    UCX_TEST_ASSERT(map->count == 3, "wrong number of properties");
+    
+    char *v1 = (char*)ucx_map_cstr_get(map, "key1");
+    char *v2 = (char*)ucx_map_cstr_get(map, "key2");
+    char *v3 = (char*)ucx_map_cstr_get(map, "key3");
+    
+    UCX_TEST_ASSERT(v1, "value for key1 not found");
+    UCX_TEST_ASSERT(v2, "value for key2 not found");
+    UCX_TEST_ASSERT(v3, "value for key3 not found");
+    
+    UCX_TEST_ASSERT((!strcmp(v1, "value1")), "wrong value for key1");
+    UCX_TEST_ASSERT((!strcmp(v2, "value2")), "wrong value for key2");
+    UCX_TEST_ASSERT((!strcmp(v3, "value3")), "wrong value for key3");
+    
+    // second test
+    ucx_map_free(map);
+    free(v1);
+    free(v2);
+    free(v3);
+    map = ucx_map_new(16);
+    
+    str = "\n#comment\n";
+    ucx_prop_fill(parser, (char*)str, strlen(str));
+    
+    r = ucx_prop_parse2map(parser, map);
+    UCX_TEST_ASSERT(r == 0, "parse2map failed");
+    UCX_TEST_ASSERT(map->count == 0, "wrong number of properties");
+    
+    str = "key1 = value1\nsyntax error line\n";
+    ucx_prop_fill(parser, (char*)str, strlen(str));
+    
+    r = ucx_prop_parse2map(parser, map);
+    UCX_TEST_ASSERT(r == 1, "parse2map should return 1");
+    UCX_TEST_ASSERT(map->count == 1, "wrong number of properties");
+    
+    char *v = (char*)ucx_map_cstr_get(map, "key1");
+    UCX_TEST_ASSERT((!strcmp(v, "value1")), "wrong value");
+    
+    UCX_TEST_END
+    
+    ucx_prop_free(parser);
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_properties_load) { 
+    UCX_TEST_BEGIN
+    FILE *f = tmpfile();
+    UCX_TEST_ASSERT(f, "test file cannot be opened, test aborted");
+    
+    fprintf(f, "# properties file\n\nkey1 = value1\nkey2 = value2\n");
+    fprintf(f, "\n\nkey3    = value3\n\n");
+    
+    size_t name_len = 512;
+    char *long_name = (char*)malloc(name_len);
+    memset(long_name, 'k', 512);
+    
+    size_t value_len = 2048;
+    char *long_value = (char*)malloc(value_len);
+    memset(long_value, 'v', 2048);
+    
+    fwrite(long_name, 1, name_len, f);
+    fprintf(f, "    =    ");
+    fwrite(long_value, 1, value_len, f);
+    fprintf(f, "                         \n");
+    
+    fprintf(f, "\n\n\n\nlast_key = property value\n");
+    
+    fflush(f);
+    fseek(f, 0, SEEK_SET);
+    
+    UcxMap *map = ucx_map_new(8);
+    int r = ucx_properties_load(map, f);
+    
+    UCX_TEST_ASSERT(r == 0, "ucx_properties_load failed");
+    UCX_TEST_ASSERT(map->count == 5, "wrong number of properties");
+    
+    char *v1 = (char*)ucx_map_cstr_get(map, "key1");
+    char *v2 = (char*)ucx_map_cstr_get(map, "key2");
+    char *v3 = (char*)ucx_map_cstr_get(map, "key3");
+    char *lv = (char*)ucx_map_sstr_get(map, sstrn(long_name, name_len));
+    char *lk = (char*)ucx_map_cstr_get(map, "last_key");
+    
+    UCX_TEST_ASSERT(v1, "value for key1 not found");
+    UCX_TEST_ASSERT(v2, "value for key2 not found");
+    UCX_TEST_ASSERT(v3, "value for key3 not found");
+    UCX_TEST_ASSERT(lv, "value for long key not found");
+    UCX_TEST_ASSERT(lk, "value for last_key not found");
+    
+    UCX_TEST_ASSERT((!strcmp(v1, "value1")), "wrong value for key1");
+    UCX_TEST_ASSERT((!strcmp(v2, "value2")), "wrong value for key2");
+    UCX_TEST_ASSERT((!strcmp(v3, "value3")), "wrong value for key3");
+    sstr_t long1 = sstrn(long_value, value_len);
+    sstr_t long2 = sstr(lv);
+    UCX_TEST_ASSERT((!sstrcmp(long1, long2)), "wrong value for long key");
+    UCX_TEST_ASSERT(!strcmp(lk, "property value"), "wrong value for last_key");
+    
+    free(v1);
+    free(v2);
+    free(v3);
+    free(lv);
+    free(lk);
+    ucx_map_free(map);
+    fclose(f);
+    
+    UCX_TEST_END
+}
+
+UCX_TEST_IMPLEMENT(test_ucx_properties_store) {
+    UcxMap *map1 = ucx_map_new(16);
+    ucx_map_cstr_put(map1, "key1", "value1");
+    ucx_map_cstr_put(map1, "key2", "value2");
+    ucx_map_cstr_put(map1, "key3", "value3");
+    ucx_map_cstr_put(map1, "key4", "value4");
+    ucx_map_cstr_put(map1, "property.key1", "some value 1");
+    ucx_map_cstr_put(map1, "property.key2", "some value 2");
+    ucx_map_cstr_put(map1, "property.key3", "some value 3");
+    ucx_map_cstr_put(map1, "property.key4", "some value 4");
+    
+    UCX_TEST_BEGIN
+    
+    FILE *f = tmpfile();
+    fprintf(f, "#\n# test property file\n#\n#\n");
+    ucx_properties_store(map1, f);
+    
+    fflush(f);
+    fseek(f, 0, SEEK_SET);
+    UcxMap *map2 = ucx_map_new(16);
+    ucx_properties_load(map2, f);
+    
+    UCX_TEST_ASSERT(map2->count == 8, "wrong number of properties in map2");
+    
+    char *v1 = (char*)ucx_map_cstr_get(map2, "key1");
+    char *v2 = (char*)ucx_map_cstr_get(map2, "key2");
+    char *v3 = (char*)ucx_map_cstr_get(map2, "key3");
+    char *v4 = (char*)ucx_map_cstr_get(map2, "key4");
+    char *v5 = (char*)ucx_map_cstr_get(map2, "property.key1");
+    char *v6 = (char*)ucx_map_cstr_get(map2, "property.key2");
+    char *v7 = (char*)ucx_map_cstr_get(map2, "property.key3");
+    char *v8 = (char*)ucx_map_cstr_get(map2, "property.key4");
+    
+    UCX_TEST_ASSERT(v1 && v2 && v3 && v4 && v5 && v6 && v7 && v8,
+            "missing values");
+    
+    UCX_TEST_ASSERT((!strcmp(v1, "value1")), "wrong value 1");
+    UCX_TEST_ASSERT((!strcmp(v2, "value2")), "wrong value 2");
+    UCX_TEST_ASSERT((!strcmp(v3, "value3")), "wrong value 3");
+    UCX_TEST_ASSERT((!strcmp(v4, "value4")), "wrong value 4");
+    UCX_TEST_ASSERT((!strcmp(v5, "some value 1")), "wrong value 5");
+    UCX_TEST_ASSERT((!strcmp(v6, "some value 2")), "wrong value 6");
+    UCX_TEST_ASSERT((!strcmp(v7, "some value 3")), "wrong value 7");
+    UCX_TEST_ASSERT((!strcmp(v8, "some value 4")), "wrong value 8");
+    
+    free(v1);
+    free(v2);
+    free(v3);
+    free(v4);
+    free(v5);
+    free(v6);
+    free(v7);
+    free(v8);
+    ucx_map_free(map2);
+    fclose(f);
+    
+    UCX_TEST_END
+    
+    ucx_map_free(map1);
+}
--- a/test/prop_tests.h	Fri Jul 12 20:50:18 2013 +0200
+++ b/test/prop_tests.h	Sun Jul 14 17:11:34 2013 +0200
@@ -41,6 +41,9 @@
 UCX_TEST_DECLARE(test_ucx_prop_parse_multi);
 UCX_TEST_DECLARE(test_ucx_prop_parse_part);
 UCX_TEST_DECLARE(test_ucx_prop_parse_long);
+UCX_TEST_DECLARE(test_ucx_prop_parse2map);
+UCX_TEST_DECLARE(test_ucx_properties_load);
+UCX_TEST_DECLARE(test_ucx_properties_store);
 
 #ifdef	__cplusplus
 }
--- a/ucx/map.h	Fri Jul 12 20:50:18 2013 +0200
+++ b/ucx/map.h	Sun Jul 14 17:11:34 2013 +0200
@@ -94,11 +94,11 @@
 void* ucx_map_remove(UcxMap *map, UcxKey key);
 
 #define ucx_map_sstr_put(m, s, d) \
-    ucx_map_put(m, ucx_key(s.ptr, s.length), d)
+    ucx_map_put(m, ucx_key(s.ptr, s.length), (void*)d)
 #define ucx_map_cstr_put(m, s, d) \
-    ucx_map_put(m, ucx_key((void*)s, strlen(s)), d)
+    ucx_map_put(m, ucx_key((void*)s, strlen(s)), (void*)d)
 #define ucx_map_int_put(m, i, d) \
-    ucx_map_put(m, ucx_key((void*)&i, sizeof(i)), d)
+    ucx_map_put(m, ucx_key((void*)&i, sizeof(i)), (void*)d)
 
 #define ucx_map_sstr_get(m, s) \
     ucx_map_get(m, ucx_key(s.ptr, s.length))
--- a/ucx/properties.c	Fri Jul 12 20:50:18 2013 +0200
+++ b/ucx/properties.c	Sun Jul 14 17:11:34 2013 +0200
@@ -45,6 +45,7 @@
     parser->tmp = NULL;
     parser->tmplen = 0;
     parser->tmpcap = 0;
+    parser->error = 0;
     parser->delimiter = '=';
     parser->comment1 = '#';
     parser->comment2 = 0;
@@ -106,7 +107,7 @@
             parser->pos = newlen;
             
             /*
-             * if ret == 0 the tmp buffer contained just space or comment
+             * if ret == 0 the tmp buffer contained just space or a comment
              * we parse again with the original buffer to get a name/value
              * or a new tmp buffer
              */
@@ -126,10 +127,7 @@
     char delimiter = parser->delimiter;
     
     // get one line and parse it
-    while(1) {
-        if(parser->pos >= parser->buflen) {
-            return 0;
-        }
+    while(parser->pos < parser->buflen) {
         char *buf = parser->buffer + parser->pos;
         size_t len = parser->buflen - parser->pos;
         
@@ -160,7 +158,7 @@
         }
 
         if(c != '\n') {
-            // we have not enough data for a line
+            // we don't have enough data for a line
             // store remaining bytes in temporary buffer for next round
             parser->tmpcap = len + 128;
             parser->tmp = (char*)malloc(parser->tmpcap);
@@ -174,31 +172,96 @@
         if(delimiter_index == 0) {
             line = sstrtrim(line);
             if(line.length != 0) {
-                // syntax error
-                // TODO
+                parser->error = 1;
             }
-            parser->pos += i + 1;
-            continue;
+        } else {
+            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) {
+                *name = n;
+                *value = v;
+                parser->pos += i + 1;
+                return 1;
+            } else {
+                parser->error = 1;
+            }
         }
         
-        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;
+        parser->pos += i + 1;
+    }
+    
+    return 0;
+}
+
+int ucx_prop_parse2map(UcxPropParser *parser, UcxMap *map) {
+    sstr_t name;
+    sstr_t value;
+    while(ucx_prop_parse(parser, &name, &value)) {
+        name = sstrdup_alloc(map->allocator, name);
+        if(!name.ptr) {
+            return 1;
         }
-        
-        *name = n;
-        *value = v;
-        
-        parser->pos += i + 1;
-        break;
+        value = sstrdup_alloc(map->allocator, value);
+        if(!value.ptr) {
+            map->allocator->free(map->allocator->pool, value.ptr);
+            return 1;
+        }
+        if(ucx_map_sstr_put(map, name, value.ptr)) {
+            map->allocator->free(map->allocator->pool, name.ptr);
+            map->allocator->free(map->allocator->pool, value.ptr);
+            return 1;
+        }
+    }
+    if(parser->error) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+int ucx_properties_load(UcxMap *map, FILE *file) {
+    UcxPropParser *parser = ucx_prop_new();
+    if(!parser || !map || !file) {
+        return 1;
     }
     
-    return 1;
+    int error = 0;
+    size_t r;
+    char buf[1024];
+    while((r = fread(buf, 1, 1024, file)) != 0) {
+        ucx_prop_fill(parser, buf, r);
+        if(ucx_prop_parse2map(parser, map)) {
+            error = 1;
+            break;
+        }
+    }
+    
+    ucx_prop_free(parser);
+    return error;
 }
 
+int ucx_properties_store(UcxMap *map, FILE *file) {
+    UcxMapIterator iter = ucx_map_iterator(map);
+    char *k, *v;
+    sstr_t key, value;
+    size_t written;
+
+    UCX_MAP_FOREACH(v, iter) {
+        k = (char*) iter.cur->key.data;
+        key = sstrn(k, iter.cur->key.len);
+        value = sstr(v);
+
+        written = 0;
+        written += fwrite(key.ptr, 1, key.length, file);
+        written += fwrite(" = ", 1, 3, file);
+        written += fwrite(value.ptr, 1, value.length, file);
+        written += fwrite("\n", 1, 1, file);
+
+        if (written != key.length + value.length + 4) return 1;
+    }
+
+    return 0;
+}
+
--- a/ucx/properties.h	Fri Jul 12 20:50:18 2013 +0200
+++ b/ucx/properties.h	Sun Jul 14 17:11:34 2013 +0200
@@ -43,6 +43,7 @@
     char   *tmp;
     size_t tmplen;
     size_t tmpcap;
+    int    error;
     char   delimiter;
     char   comment1;
     char   comment2;
@@ -54,6 +55,10 @@
 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);
+int ucx_prop_parse2map(UcxPropParser *parser, UcxMap *map);
+
+int ucx_properties_load(UcxMap *map, FILE *file);
+int ucx_properties_store(UcxMap *map, FILE *file);
 
 #ifdef	__cplusplus
 }
--- a/ucx/string.c	Fri Jul 12 20:50:18 2013 +0200
+++ b/ucx/string.c	Sun Jul 14 17:11:34 2013 +0200
@@ -31,6 +31,7 @@
 #include <stdarg.h>
 
 #include "string.h"
+#include "allocator.h"
 
 sstr_t sstr(char *s) {
     sstr_t string;
@@ -180,16 +181,30 @@
 sstr_t sstrdup(sstr_t s) {
     sstr_t newstring;
     newstring.ptr = (char*) malloc(s.length + 1);
-    newstring.length = 0;
     if (newstring.ptr) {
         newstring.length = s.length;
         newstring.ptr[newstring.length] = 0;
-
+        
         memcpy(newstring.ptr, s.ptr, s.length);
     } else {
         newstring.length = 0;
     }
+    
+    return newstring;
+}
 
+sstr_t sstrdup_alloc(UcxAllocator *allocator, sstr_t s) {
+    sstr_t newstring;
+    newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1);
+    if (newstring.ptr) {
+        newstring.length = s.length;
+        newstring.ptr[newstring.length] = 0;
+        
+        memcpy(newstring.ptr, s.ptr, s.length);
+    } else {
+        newstring.length = 0;
+    }
+    
     return newstring;
 }
 
--- a/ucx/string.h	Fri Jul 12 20:50:18 2013 +0200
+++ b/ucx/string.h	Sun Jul 14 17:11:34 2013 +0200
@@ -30,6 +30,7 @@
 #define	_SSTRING_H
 
 #include "ucx.h"
+#include "allocator.h"
 #include <stddef.h>
 
 /* use macros for literals only */
@@ -117,6 +118,7 @@
 int sstrcmp(sstr_t s1, sstr_t s2);
 
 sstr_t sstrdup(sstr_t s);
+sstr_t sstrdup_alloc(UcxAllocator *allocator, sstr_t s);
 
 sstr_t sstrtrim(sstr_t string);
 

mercurial