Fri, 12 Jul 2013 20:50:18 +0200
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;