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
     1.1 --- a/g++-debug.mk	Thu Jul 11 17:32:48 2013 +0200
     1.2 +++ b/g++-debug.mk	Fri Jul 12 20:50:18 2013 +0200
     1.3 @@ -31,7 +31,7 @@
     1.4  AR = ar
     1.5  RM = rm
     1.6  
     1.7 -CFLAGS  = -std=gnu++0x -g -O2 -fstrict-aliasing -Wall -pedantic -c
     1.8 +CFLAGS  = -std=gnu++0x -g -fstrict-aliasing -Wall -pedantic -c
     1.9  COFLAGS = -o
    1.10  LDFLAGS = 
    1.11  LOFLAGS = -o
     2.1 --- a/gcc-debug.mk	Thu Jul 11 17:32:48 2013 +0200
     2.2 +++ b/gcc-debug.mk	Fri Jul 12 20:50:18 2013 +0200
     2.3 @@ -31,7 +31,7 @@
     2.4  AR = ar
     2.5  RM = rm
     2.6  
     2.7 -CFLAGS  = -std=gnu99 -g -O2 -fstrict-aliasing -Wall -pedantic -c
     2.8 +CFLAGS  = -std=gnu99 -g -fstrict-aliasing -Wall -pedantic -c
     2.9  COFLAGS = -o
    2.10  LDFLAGS = 
    2.11  LOFLAGS = -o
     3.1 --- a/test/Makefile	Thu Jul 11 17:32:48 2013 +0200
     3.2 +++ b/test/Makefile	Fri Jul 12 20:50:18 2013 +0200
     3.3 @@ -33,6 +33,7 @@
     3.4  SRC += dlist_tests.c
     3.5  SRC += mpool_tests.c
     3.6  SRC += map_tests.c
     3.7 +SRC += prop_tests.c
     3.8  SRC += string_tests.c
     3.9  SRC += logging_tests.c
    3.10  SRC += buffer_tests.c
     4.1 --- a/test/main.c	Thu Jul 11 17:32:48 2013 +0200
     4.2 +++ b/test/main.c	Fri Jul 12 20:50:18 2013 +0200
     4.3 @@ -39,6 +39,7 @@
     4.4  #include "string_tests.h"
     4.5  #include "mpool_tests.h"
     4.6  #include "map_tests.h"
     4.7 +#include "prop_tests.h"
     4.8  #include "buffer_tests.h"
     4.9  
    4.10  UCX_TEST_IMPLEMENT(testTestSuitePositive) {
    4.11 @@ -168,8 +169,15 @@
    4.12          ucx_test_register(suite, test_ucx_map_store_load_with_mempool);
    4.13          ucx_test_register(suite, test_ucx_map_clone);
    4.14          ucx_test_register(suite, test_ucx_map_rehash);
    4.15 -
    4.16 -        /* UcxMemstream Tests */
    4.17 +        
    4.18 +        /* UcxPropertiesParser Tests */
    4.19 +        ucx_test_register(suite, test_ucx_prop_new);
    4.20 +        ucx_test_register(suite, test_ucx_prop_parse);
    4.21 +        ucx_test_register(suite, test_ucx_prop_parse_multi);
    4.22 +        ucx_test_register(suite, test_ucx_prop_parse_part);
    4.23 +        ucx_test_register(suite, test_ucx_prop_parse_long);
    4.24 +        
    4.25 +        /* UcxBuffer Tests */
    4.26          ucx_test_register(suite, test_ucx_buffer_seektell);
    4.27          ucx_test_register(suite, test_ucx_buffer_putc);
    4.28          ucx_test_register(suite, test_ucx_buffer_putc_ax);
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/prop_tests.c	Fri Jul 12 20:50:18 2013 +0200
     5.3 @@ -0,0 +1,362 @@
     5.4 +/*
     5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 + *
     5.7 + * Copyright 2013 Olaf Wintermann. All rights reserved.
     5.8 + *
     5.9 + * Redistribution and use in source and binary forms, with or without
    5.10 + * modification, are permitted provided that the following conditions are met:
    5.11 + *
    5.12 + *   1. Redistributions of source code must retain the above copyright
    5.13 + *      notice, this list of conditions and the following disclaimer.
    5.14 + *
    5.15 + *   2. Redistributions in binary form must reproduce the above copyright
    5.16 + *      notice, this list of conditions and the following disclaimer in the
    5.17 + *      documentation and/or other materials provided with the distribution.
    5.18 + *
    5.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    5.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    5.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    5.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    5.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    5.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    5.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    5.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    5.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    5.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    5.29 + * POSSIBILITY OF SUCH DAMAGE.
    5.30 + */
    5.31 +
    5.32 +#include "prop_tests.h"
    5.33 +
    5.34 +UCX_TEST_IMPLEMENT(test_ucx_prop_new) {
    5.35 +    UcxPropParser *parser = ucx_prop_new();
    5.36 +    
    5.37 +    UCX_TEST_BEGIN
    5.38 +            
    5.39 +    UCX_TEST_ASSERT(parser != NULL, "failed");
    5.40 +    UCX_TEST_ASSERT(parser->buffer == NULL, "parser has buffer");
    5.41 +    UCX_TEST_ASSERT(parser->tmp == NULL, "parser has tmp buffer");
    5.42 +    
    5.43 +    UCX_TEST_END
    5.44 +            
    5.45 +    ucx_prop_free(parser);
    5.46 +}
    5.47 +
    5.48 +UCX_TEST_IMPLEMENT(test_ucx_prop_parse) {  
    5.49 +    char *tests[] = {
    5.50 +        "name = value\n",
    5.51 +        "name=value\n",
    5.52 +        "n=value\n",
    5.53 +        "name=v\n",
    5.54 +        "n=v\n",
    5.55 +        "name = value # comment\n",
    5.56 +        "#comment\nn=v\n",
    5.57 +        "# comment1\n# comment2\n\n    \n\nname = value\n",
    5.58 +        "    name     =      value\n",
    5.59 +        "name = value\n\n"
    5.60 +    };
    5.61 +    
    5.62 +    char *names[] = {
    5.63 +        "name",
    5.64 +        "name",
    5.65 +        "n",
    5.66 +        "name",
    5.67 +        "n",
    5.68 +        "name",
    5.69 +        "n",
    5.70 +        "name",
    5.71 +        "name",
    5.72 +        "name"
    5.73 +    };
    5.74 +    
    5.75 +    char *values[] = {
    5.76 +        "value",
    5.77 +        "value",
    5.78 +        "value",
    5.79 +        "v",
    5.80 +        "v",
    5.81 +        "value",
    5.82 +        "v",
    5.83 +        "value",
    5.84 +        "value",
    5.85 +        "value"
    5.86 +    };
    5.87 +    
    5.88 +    UCX_TEST_BEGIN
    5.89 +    
    5.90 +    sstr_t name;
    5.91 +    sstr_t value;
    5.92 +    
    5.93 +    for(int i=0;i<10;i++) {
    5.94 +        UcxPropParser *parser = ucx_prop_new();
    5.95 +        
    5.96 +        ucx_prop_fill(parser, tests[i], strlen(tests[i]));
    5.97 +        UCX_TEST_ASSERT(parser->buffer == tests[i], "fill failed");
    5.98 +        UCX_TEST_ASSERT(parser->buflen == strlen(tests[i]), "wrong buflen");
    5.99 +        
   5.100 +        int r = ucx_prop_parse(parser, &name, &value);
   5.101 +        sstr_t n = sstr(names[i]);
   5.102 +        sstr_t v = sstr(values[i]);
   5.103 +        UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.104 +        UCX_TEST_ASSERT((!sstrcmp(name, n)), "wrong property name");
   5.105 +        UCX_TEST_ASSERT((!sstrcmp(value, v)), "wrong property value");
   5.106 +        
   5.107 +        r = ucx_prop_parse(parser, &name, &value);
   5.108 +        UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.109 +        UCX_TEST_ASSERT(parser->tmp == NULL, "tmp not NULL");
   5.110 +        UCX_TEST_ASSERT(parser->tmpcap == 0, "tmpcap not NULL");
   5.111 +        UCX_TEST_ASSERT(parser->tmplen == 0, "tmplen not NULL");
   5.112 +        
   5.113 +        ucx_prop_free(parser);
   5.114 +    }
   5.115 +    
   5.116 +    UCX_TEST_END       
   5.117 +}
   5.118 +
   5.119 +UCX_TEST_IMPLEMENT(test_ucx_prop_parse_multi) {
   5.120 +    char *names[] = {
   5.121 +        "a",
   5.122 +        "b",
   5.123 +        "c",
   5.124 +        "uap",
   5.125 +        "name",
   5.126 +        "key1",
   5.127 +        "key2",
   5.128 +        "key3"
   5.129 +    };
   5.130 +    
   5.131 +    char *values[] = {
   5.132 +        "a value",
   5.133 +        "b value",
   5.134 +        "core",
   5.135 +        "core",
   5.136 +        "ucx",
   5.137 +        "value1",
   5.138 +        "value2",
   5.139 +        "value3"
   5.140 +    };
   5.141 +    
   5.142 +    char *str = "#\n"
   5.143 +        "# properties\n"
   5.144 +        "# contains key/value pairs\n"
   5.145 +        "#\n"
   5.146 +        "a = a value\n"
   5.147 +        "b = b value\n"
   5.148 +        "c = core\n"
   5.149 +        "\n# test\n"
   5.150 +        "uap = core\n"
   5.151 +        "name = ucx\n"
   5.152 +        "# no = property\n"
   5.153 +        "key1 = value1\n"
   5.154 +        "#key1 = wrong value\n"
   5.155 +        "#key2 = not value 2\n"
   5.156 +        "key2 = value2\n"
   5.157 +        "\n\n\n        \n           key3=value3\n";
   5.158 +    
   5.159 +    UcxPropParser *parser = ucx_prop_new();
   5.160 +    
   5.161 +    UCX_TEST_BEGIN
   5.162 +    
   5.163 +    ucx_prop_fill(parser, str, strlen(str));
   5.164 +    
   5.165 +    sstr_t name;
   5.166 +    sstr_t value;
   5.167 +    for(int i=0;i<8;i++) {
   5.168 +        int r = ucx_prop_parse(parser, &name, &value);
   5.169 +        UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.170 +        UCX_TEST_ASSERT((!sstrcmp(name, sstr(names[i]))), "wrong name");
   5.171 +        UCX_TEST_ASSERT((!sstrcmp(value, sstr(values[i]))), "wrong value");
   5.172 +    }
   5.173 +    int r = ucx_prop_parse(parser, &name, &value);
   5.174 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.175 +    
   5.176 +    UCX_TEST_END
   5.177 +    
   5.178 +    ucx_prop_free(parser);
   5.179 +}
   5.180 +
   5.181 +UCX_TEST_IMPLEMENT(test_ucx_prop_parse_part) {
   5.182 +    UcxPropParser *parser = ucx_prop_new();
   5.183 +    char *str;
   5.184 +    int r;
   5.185 +    sstr_t name;
   5.186 +    sstr_t value;
   5.187 +    
   5.188 +    UCX_TEST_BEGIN
   5.189 +    
   5.190 +    str = "";
   5.191 +    ucx_prop_fill(parser, str, strlen(str));
   5.192 +    r = ucx_prop_parse(parser, &name, &value);
   5.193 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.194 +    
   5.195 +    str = "  \n";
   5.196 +    ucx_prop_fill(parser, str, strlen(str));
   5.197 +    r = ucx_prop_parse(parser, &name, &value); 
   5.198 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.199 +    
   5.200 +    str = "name";
   5.201 +    ucx_prop_fill(parser, str, strlen(str));
   5.202 +    r = ucx_prop_parse(parser, &name, &value); 
   5.203 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.204 +    
   5.205 +    str = "    ";
   5.206 +    ucx_prop_fill(parser, str, strlen(str));
   5.207 +    r = ucx_prop_parse(parser, &name, &value); 
   5.208 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.209 +    
   5.210 +    str = "= ";
   5.211 +    ucx_prop_fill(parser, str, strlen(str));
   5.212 +    r = ucx_prop_parse(parser, &name, &value); 
   5.213 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.214 +    
   5.215 +    str = "value";
   5.216 +    ucx_prop_fill(parser, str, strlen(str));
   5.217 +    r = ucx_prop_parse(parser, &name, &value); 
   5.218 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.219 +    
   5.220 +    str = "\n";
   5.221 +    ucx_prop_fill(parser, str, strlen(str));
   5.222 +    r = ucx_prop_parse(parser, &name, &value); 
   5.223 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.224 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("name"))), "wrong name");
   5.225 +    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
   5.226 +    
   5.227 +    // second round
   5.228 +    str = "#comment\n";
   5.229 +    ucx_prop_fill(parser, str, strlen(str));
   5.230 +    r = ucx_prop_parse(parser, &name, &value); 
   5.231 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.232 +    
   5.233 +    str = "#comment\nname = ";
   5.234 +    ucx_prop_fill(parser, str, strlen(str));
   5.235 +    r = ucx_prop_parse(parser, &name, &value); 
   5.236 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.237 +    
   5.238 +    str = "value\na = b\n";
   5.239 +    ucx_prop_fill(parser, str, strlen(str));
   5.240 +    r = ucx_prop_parse(parser, &name, &value); 
   5.241 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.242 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("name"))), "wrong name");
   5.243 +    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
   5.244 +    
   5.245 +    r = ucx_prop_parse(parser, &name, &value); 
   5.246 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.247 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("a"))), "wrong name");
   5.248 +    UCX_TEST_ASSERT((!sstrcmp(value, sstr("b"))), "wrong value");
   5.249 +    
   5.250 +    str = "# comment\n#\n#\ntests = ";
   5.251 +    ucx_prop_fill(parser, str, strlen(str));
   5.252 +    r = ucx_prop_parse(parser, &name, &value); 
   5.253 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.254 +    
   5.255 +    str = "test1 ";
   5.256 +    ucx_prop_fill(parser, str, strlen(str));
   5.257 +    r = ucx_prop_parse(parser, &name, &value); 
   5.258 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.259 +    
   5.260 +    str = "test2 test3 test4\n";
   5.261 +    sstr_t testv = sstr("test1 test2 test3 test4");
   5.262 +    ucx_prop_fill(parser, str, strlen(str));
   5.263 +    r = ucx_prop_parse(parser, &name, &value); 
   5.264 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.265 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("tests"))), "wrong name");
   5.266 +    UCX_TEST_ASSERT((!sstrcmp(value, testv)), "wrong value");
   5.267 +    
   5.268 +    // test if parse finds a name/value after a tmp comment
   5.269 +    str = "# just a comment";
   5.270 +    ucx_prop_fill(parser, str, strlen(str));
   5.271 +    r = ucx_prop_parse(parser, &name, &value); 
   5.272 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.273 +    
   5.274 +    str = " in 3";
   5.275 +    ucx_prop_fill(parser, str, strlen(str));
   5.276 +    r = ucx_prop_parse(parser, &name, &value); 
   5.277 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.278 +    
   5.279 +    str = " parts\na = 1\n";
   5.280 +    ucx_prop_fill(parser, str, strlen(str));
   5.281 +    r = ucx_prop_parse(parser, &name, &value); 
   5.282 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.283 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("a"))), "wrong name");
   5.284 +    UCX_TEST_ASSERT((!sstrcmp(value, sstr("1"))), "wrong value");
   5.285 +    
   5.286 +    UCX_TEST_END
   5.287 +    
   5.288 +    ucx_prop_free(parser);
   5.289 +}
   5.290 +
   5.291 +UCX_TEST_IMPLEMENT(test_ucx_prop_parse_long) {
   5.292 +    UcxPropParser *parser = ucx_prop_new();
   5.293 +    int r;
   5.294 +    size_t name_len = 512;
   5.295 +    char *long_name = (char*)malloc(name_len);
   5.296 +    memset(long_name, 'a', 70);
   5.297 +    memset(long_name+70, 'b', 242);
   5.298 +    memset(long_name+312, 'c', 200);
   5.299 +    
   5.300 +    size_t value_len = 2048;
   5.301 +    char *long_value = (char*)malloc(value_len);
   5.302 +    memset(long_value, 'x', 1024);
   5.303 +    memset(long_value+1024, 'y', 1024);
   5.304 +    
   5.305 +    UCX_TEST_BEGIN
   5.306 +    
   5.307 +    sstr_t name;
   5.308 +    sstr_t value;
   5.309 +    
   5.310 +    ucx_prop_fill(parser, long_name, 10);
   5.311 +    r = ucx_prop_parse(parser, &name, &value);
   5.312 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.313 +    
   5.314 +    ucx_prop_fill(parser, long_name+10, 202);
   5.315 +    r = ucx_prop_parse(parser, &name, &value);
   5.316 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.317 +    
   5.318 +    ucx_prop_fill(parser, long_name+212, 200);
   5.319 +    r = ucx_prop_parse(parser, &name, &value);
   5.320 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.321 +    
   5.322 +    ucx_prop_fill(parser, long_name+412, 100);
   5.323 +    r = ucx_prop_parse(parser, &name, &value);
   5.324 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.325 +    
   5.326 +    char *str = " = ";
   5.327 +    ucx_prop_fill(parser, str, strlen(str));
   5.328 +    r = ucx_prop_parse(parser, &name, &value);
   5.329 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.330 +    
   5.331 +    ucx_prop_fill(parser, long_value, 512);
   5.332 +    r = ucx_prop_parse(parser, &name, &value); 
   5.333 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.334 +    
   5.335 +    ucx_prop_fill(parser, long_value+512, 1024);
   5.336 +    r = ucx_prop_parse(parser, &name, &value);
   5.337 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.338 +    
   5.339 +    ucx_prop_fill(parser, long_value+1536, 512);
   5.340 +    r = ucx_prop_parse(parser, &name, &value);
   5.341 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.342 +    
   5.343 +    str = "\n#comment\nkey = value\n";
   5.344 +    ucx_prop_fill(parser, str, strlen(str));    
   5.345 +    r = ucx_prop_parse(parser, &name, &value);
   5.346 +    sstr_t n = sstrn(long_name, name_len);
   5.347 +    sstr_t v = sstrn(long_value, value_len);
   5.348 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.349 +    UCX_TEST_ASSERT((!sstrcmp(name, n)), "wrong name");
   5.350 +    UCX_TEST_ASSERT((!sstrcmp(value, v)), "wrong value");
   5.351 +    
   5.352 +    r = ucx_prop_parse(parser, &name, &value);
   5.353 +    UCX_TEST_ASSERT(r == 1, "parse returned 0");
   5.354 +    UCX_TEST_ASSERT((!sstrcmp(name, sstr("key"))), "wrong name");
   5.355 +    UCX_TEST_ASSERT((!sstrcmp(value, sstr("value"))), "wrong value");
   5.356 +    
   5.357 +    r = ucx_prop_parse(parser, &name, &value);
   5.358 +    UCX_TEST_ASSERT(r == 0, "parse returned 1");
   5.359 +    
   5.360 +    UCX_TEST_END
   5.361 +    
   5.362 +    free(long_name);
   5.363 +    free(long_value);
   5.364 +    ucx_prop_free(parser);
   5.365 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/prop_tests.h	Fri Jul 12 20:50:18 2013 +0200
     6.3 @@ -0,0 +1,50 @@
     6.4 +/*
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright 2013 Olaf Wintermann. All rights reserved.
     6.8 + *
     6.9 + * Redistribution and use in source and binary forms, with or without
    6.10 + * modification, are permitted provided that the following conditions are met:
    6.11 + *
    6.12 + *   1. Redistributions of source code must retain the above copyright
    6.13 + *      notice, this list of conditions and the following disclaimer.
    6.14 + *
    6.15 + *   2. Redistributions in binary form must reproduce the above copyright
    6.16 + *      notice, this list of conditions and the following disclaimer in the
    6.17 + *      documentation and/or other materials provided with the distribution.
    6.18 + *
    6.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    6.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    6.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    6.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    6.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    6.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    6.29 + * POSSIBILITY OF SUCH DAMAGE.
    6.30 + */
    6.31 +
    6.32 +#ifndef PROP_TESTS_H
    6.33 +#define	PROP_TESTS_H
    6.34 +
    6.35 +#include "ucx/test.h"
    6.36 +#include "ucx/properties.h"
    6.37 +
    6.38 +#ifdef	__cplusplus
    6.39 +extern "C" {
    6.40 +#endif
    6.41 +
    6.42 +UCX_TEST_DECLARE(test_ucx_prop_new);
    6.43 +UCX_TEST_DECLARE(test_ucx_prop_parse);
    6.44 +UCX_TEST_DECLARE(test_ucx_prop_parse_multi);
    6.45 +UCX_TEST_DECLARE(test_ucx_prop_parse_part);
    6.46 +UCX_TEST_DECLARE(test_ucx_prop_parse_long);
    6.47 +
    6.48 +#ifdef	__cplusplus
    6.49 +}
    6.50 +#endif
    6.51 +
    6.52 +#endif	/* PROP_TESTS_H */
    6.53 +
     7.1 --- a/ucx/Makefile	Thu Jul 11 17:32:48 2013 +0200
     7.2 +++ b/ucx/Makefile	Fri Jul 12 20:50:18 2013 +0200
     7.3 @@ -33,6 +33,7 @@
     7.4  SRC += list.c 
     7.5  SRC += dlist.c
     7.6  SRC += map.c
     7.7 +SRC += properties.c
     7.8  SRC += mempool.c
     7.9  SRC += string.c
    7.10  SRC += test.c
     8.1 --- a/ucx/map.c	Thu Jul 11 17:32:48 2013 +0200
     8.2 +++ b/ucx/map.c	Fri Jul 12 20:50:18 2013 +0200
     8.3 @@ -39,7 +39,7 @@
     8.4      if(size == 0) {
     8.5          size = 16;
     8.6      }
     8.7 -    
     8.8 +       
     8.9      if(!allocator) {
    8.10          allocator = ucx_default_allocator();
    8.11      }
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/ucx/properties.c	Fri Jul 12 20:50:18 2013 +0200
     9.3 @@ -0,0 +1,204 @@
     9.4 +/*
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 2013 Olaf Wintermann. All rights reserved.
     9.8 + *
     9.9 + * Redistribution and use in source and binary forms, with or without
    9.10 + * modification, are permitted provided that the following conditions are met:
    9.11 + *
    9.12 + *   1. Redistributions of source code must retain the above copyright
    9.13 + *      notice, this list of conditions and the following disclaimer.
    9.14 + *
    9.15 + *   2. Redistributions in binary form must reproduce the above copyright
    9.16 + *      notice, this list of conditions and the following disclaimer in the
    9.17 + *      documentation and/or other materials provided with the distribution.
    9.18 + *
    9.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    9.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    9.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    9.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    9.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    9.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    9.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    9.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    9.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    9.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    9.29 + * POSSIBILITY OF SUCH DAMAGE.
    9.30 + */
    9.31 +
    9.32 +#include <stdio.h>
    9.33 +#include <stdlib.h>
    9.34 +#include <string.h>
    9.35 +
    9.36 +#include "properties.h"
    9.37 +
    9.38 +UcxPropParser *ucx_prop_new() {
    9.39 +    UcxPropParser *parser = (UcxPropParser*)malloc(
    9.40 +            sizeof(UcxPropParser));
    9.41 +    if(!parser) {
    9.42 +        return NULL;
    9.43 +    }
    9.44 +    
    9.45 +    parser->buffer = NULL;
    9.46 +    parser->buflen = 0;
    9.47 +    parser->pos = 0;
    9.48 +    parser->tmp = NULL;
    9.49 +    parser->tmplen = 0;
    9.50 +    parser->tmpcap = 0;
    9.51 +    parser->delimiter = '=';
    9.52 +    parser->comment1 = '#';
    9.53 +    parser->comment2 = 0;
    9.54 +    parser->comment3 = 0;   
    9.55 +    
    9.56 +    return parser;
    9.57 +}
    9.58 +
    9.59 +void ucx_prop_free(UcxPropParser *parser) {
    9.60 +    if(parser->tmp) {
    9.61 +        free(parser->tmp);
    9.62 +    }
    9.63 +    free(parser);
    9.64 +}
    9.65 +
    9.66 +void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len) {
    9.67 +    parser->buffer = buf;
    9.68 +    parser->buflen = len;
    9.69 +    parser->pos = 0;
    9.70 +}
    9.71 +
    9.72 +static void parser_tmp_append(UcxPropParser *parser, char *buf, size_t len) {
    9.73 +    if(parser->tmpcap - parser->tmplen < len) {
    9.74 +        size_t newcap = parser->tmpcap + len + 64;
    9.75 +        parser->tmp = (char*)realloc(parser->tmp, newcap);
    9.76 +        parser->tmpcap = newcap;
    9.77 +    }
    9.78 +    memcpy(parser->tmp + parser->tmplen, buf, len);
    9.79 +    parser->tmplen += len;
    9.80 +}
    9.81 +
    9.82 +int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value)  {   
    9.83 +    if(parser->tmplen > 0) {
    9.84 +        char *buf = parser->buffer + parser->pos;
    9.85 +        size_t len = parser->buflen - parser->pos;
    9.86 +        sstr_t str = sstrn(buf, len);
    9.87 +        sstr_t nl = sstrchr(str, '\n');
    9.88 +        if(nl.ptr) {
    9.89 +            size_t newlen = (size_t)(nl.ptr - buf) + 1;
    9.90 +            parser_tmp_append(parser, buf, newlen);
    9.91 +            // the tmp buffer contains exactly one line now
    9.92 +            
    9.93 +            char *orig_buf = parser->buffer;
    9.94 +            size_t orig_len = parser->buflen;
    9.95 +            
    9.96 +            parser->buffer = parser->tmp;
    9.97 +            parser->buflen = parser->tmplen;
    9.98 +            parser->pos = 0;    
    9.99 +            parser->tmp = NULL;
   9.100 +            parser->tmpcap = 0;
   9.101 +            parser->tmplen = 0;
   9.102 +            // run parse with the tmp buffer as main buffer
   9.103 +            int ret = ucx_prop_parse(parser, name, value);
   9.104 +            
   9.105 +            // restore original buffer
   9.106 +            parser->tmp = parser->buffer;
   9.107 +            parser->buffer = orig_buf;
   9.108 +            parser->buflen = orig_len;
   9.109 +            parser->pos = newlen;
   9.110 +            
   9.111 +            /*
   9.112 +             * if ret == 0 the tmp buffer contained just space or comment
   9.113 +             * we parse again with the original buffer to get a name/value
   9.114 +             * or a new tmp buffer
   9.115 +             */
   9.116 +            return ret ? ret : ucx_prop_parse(parser, name, value);
   9.117 +        } else {
   9.118 +            parser_tmp_append(parser, buf, len);
   9.119 +            return 0;
   9.120 +        }
   9.121 +    } else if(parser->tmp) {
   9.122 +        free(parser->tmp);
   9.123 +        parser->tmp = NULL;
   9.124 +    }
   9.125 +    
   9.126 +    char comment1 = parser->comment1;
   9.127 +    char comment2 = parser->comment2;
   9.128 +    char comment3 = parser->comment3;
   9.129 +    char delimiter = parser->delimiter;
   9.130 +    
   9.131 +    // get one line and parse it
   9.132 +    while(1) {
   9.133 +        if(parser->pos >= parser->buflen) {
   9.134 +            return 0;
   9.135 +        }
   9.136 +        char *buf = parser->buffer + parser->pos;
   9.137 +        size_t len = parser->buflen - parser->pos;
   9.138 +        
   9.139 +        /*
   9.140 +         * First we check if we have at least one line. We also get indices of
   9.141 +         * delimiter and comment chars
   9.142 +         */
   9.143 +        size_t delimiter_index = 0;
   9.144 +        size_t comment_index = 0;
   9.145 +        int has_comment = 0;
   9.146 +
   9.147 +        size_t i = 0;
   9.148 +        char c = 0;
   9.149 +        for(;i<len;i++) {
   9.150 +            c = buf[i];
   9.151 +            if(c == comment1 || c == comment2 || c == comment3) {
   9.152 +                if(comment_index == 0) {
   9.153 +                    comment_index = i;
   9.154 +                    has_comment = 1;
   9.155 +                }
   9.156 +            } else if(c == delimiter) {
   9.157 +                if(delimiter_index == 0 && !has_comment) {
   9.158 +                    delimiter_index = i;
   9.159 +                }
   9.160 +            } else if(c == '\n') {
   9.161 +                break;
   9.162 +            }
   9.163 +        }
   9.164 +
   9.165 +        if(c != '\n') {
   9.166 +            // we have not enough data for a line
   9.167 +            // store remaining bytes in temporary buffer for next round
   9.168 +            parser->tmpcap = len + 128;
   9.169 +            parser->tmp = (char*)malloc(parser->tmpcap);
   9.170 +            parser->tmplen = len;
   9.171 +            memcpy(parser->tmp, buf, len);
   9.172 +            return 0;
   9.173 +        }
   9.174 +        
   9.175 +        sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i);
   9.176 +        // check line
   9.177 +        if(delimiter_index == 0) {
   9.178 +            line = sstrtrim(line);
   9.179 +            if(line.length != 0) {
   9.180 +                // syntax error
   9.181 +                // TODO
   9.182 +            }
   9.183 +            parser->pos += i + 1;
   9.184 +            continue;
   9.185 +        }
   9.186 +        
   9.187 +        sstr_t n = sstrn(buf, delimiter_index);
   9.188 +        sstr_t v = sstrn(buf + delimiter_index + 1, i - delimiter_index - 1); 
   9.189 +        n = sstrtrim(n);
   9.190 +        v = sstrtrim(v);      
   9.191 +        if(n.length == 0 || v.length == 0) {
   9.192 +            // syntax error
   9.193 +            // TODO
   9.194 +            parser->pos += i + 1;
   9.195 +            continue;
   9.196 +        }
   9.197 +        
   9.198 +        *name = n;
   9.199 +        *value = v;
   9.200 +        
   9.201 +        parser->pos += i + 1;
   9.202 +        break;
   9.203 +    }
   9.204 +    
   9.205 +    return 1;
   9.206 +}
   9.207 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/ucx/properties.h	Fri Jul 12 20:50:18 2013 +0200
    10.3 @@ -0,0 +1,63 @@
    10.4 +/*
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright 2013 Olaf Wintermann. All rights reserved.
    10.8 + *
    10.9 + * Redistribution and use in source and binary forms, with or without
   10.10 + * modification, are permitted provided that the following conditions are met:
   10.11 + *
   10.12 + *   1. Redistributions of source code must retain the above copyright
   10.13 + *      notice, this list of conditions and the following disclaimer.
   10.14 + *
   10.15 + *   2. Redistributions in binary form must reproduce the above copyright
   10.16 + *      notice, this list of conditions and the following disclaimer in the
   10.17 + *      documentation and/or other materials provided with the distribution.
   10.18 + *
   10.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   10.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   10.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   10.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   10.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   10.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   10.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   10.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   10.29 + * POSSIBILITY OF SUCH DAMAGE.
   10.30 + */
   10.31 +
   10.32 +#ifndef PROPERTIES_H
   10.33 +#define	PROPERTIES_H
   10.34 +
   10.35 +#include "ucx.h"
   10.36 +#include "map.h"
   10.37 +
   10.38 +#ifdef	__cplusplus
   10.39 +extern "C" {
   10.40 +#endif
   10.41 +
   10.42 +typedef struct {
   10.43 +    char   *buffer;
   10.44 +    size_t buflen;
   10.45 +    size_t pos;
   10.46 +    char   *tmp;
   10.47 +    size_t tmplen;
   10.48 +    size_t tmpcap;
   10.49 +    char   delimiter;
   10.50 +    char   comment1;
   10.51 +    char   comment2;
   10.52 +    char   comment3;
   10.53 +} UcxPropParser;
   10.54 +
   10.55 +
   10.56 +UcxPropParser *ucx_prop_new();
   10.57 +void ucx_prop_free(UcxPropParser *parser);
   10.58 +void ucx_prop_fill(UcxPropParser *parser, char *buf, size_t len);
   10.59 +int ucx_prop_parse(UcxPropParser *parser, sstr_t *name, sstr_t *value);
   10.60 +
   10.61 +#ifdef	__cplusplus
   10.62 +}
   10.63 +#endif
   10.64 +
   10.65 +#endif	/* PROPERTIES_H */
   10.66 +
    11.1 --- a/ucx/string.c	Thu Jul 11 17:32:48 2013 +0200
    11.2 +++ b/ucx/string.c	Fri Jul 12 20:50:18 2013 +0200
    11.3 @@ -106,6 +106,18 @@
    11.4      return new_sstr;
    11.5  }
    11.6  
    11.7 +sstr_t sstrchr(sstr_t s, int c) {
    11.8 +    for(size_t i=0;i<s.length;i++) {
    11.9 +        if(s.ptr[i] == c) {
   11.10 +            return sstrsubs(s, i);
   11.11 +        }
   11.12 +    }
   11.13 +    sstr_t n;
   11.14 +    n.ptr = NULL;
   11.15 +    n.length = 0;
   11.16 +    return n;
   11.17 +}
   11.18 +
   11.19  sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
   11.20      if (d.length == 0) {
   11.21          return NULL;
    12.1 --- a/ucx/string.h	Thu Jul 11 17:32:48 2013 +0200
    12.2 +++ b/ucx/string.h	Fri Jul 12 20:50:18 2013 +0200
    12.3 @@ -92,6 +92,11 @@
    12.4  sstr_t sstrsubsl(sstr_t s, size_t start, size_t length);
    12.5  
    12.6  /*
    12.7 + * 
    12.8 + */
    12.9 +sstr_t sstrchr(sstr_t s, int c);
   12.10 +
   12.11 +/*
   12.12   * splits s into n parts
   12.13   *
   12.14   * s    the string to split

mercurial