From 4ec6006b64a36a2451aae1edad229baad4b8527a Mon Sep 17 00:00:00 2001 From: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu, 1 Nov 2012 14:53:49 +0100 Subject: [PATCH] New easy xml interface Squashed commit of the following: commit 7300b93a1ffaf69f6af257c83ca1b486bccce5b0 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:51:19 2012 +0100 Easy development... commit 66b764840d94bb8106a68b425ad85890efe3bba3 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:50:11 2012 +0100 Easy development... commit 62e4801612cf3a5852057718f0ade6f8c12b2f18 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:47:26 2012 +0100 Easy development... commit d3b67262ff57f765e39808b47f3329bf9ec493bc Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:47:08 2012 +0100 Easy development... commit 65661e2ac0d938fe7f5e98e0d6e6531ed812807a Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:45:05 2012 +0100 Easy development... commit 3ae765fd82342564b2be740a931637fe66ebb706 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:44:58 2012 +0100 Easy development... commit c6d1a3bb2c5f3900b1f5f4d5f1d4ffe132b0f3bd Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:44:36 2012 +0100 Easy development... commit deb98462367776b762a2dc6d01d0f86a3c053602 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:44:13 2012 +0100 Easy development... commit 53cb08c3fc47c8b076bb07c2ab8776df38565de8 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:43:41 2012 +0100 Easy development... commit ce3766de258290017b121eafa4d832443cdcc19b Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:40:47 2012 +0100 Easy development... commit 9df056a6a0b5e264e5608d6649760f434e1d66a1 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:37:59 2012 +0100 Easy interface... commit c6b1797f0a472dc529b32676070db471974ad26d Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:37:49 2012 +0100 Easy interface... commit b72f20c42d311880992c3d5e81483063ede5533c Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:37:32 2012 +0100 Easy interface... commit 9d9e3994a328b1f18271d4f3076a4a0db5828e38 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:36:52 2012 +0100 Easy interface... commit fe43225e7dbd2fc1d86d569f024b7dc80238189b Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:36:18 2012 +0100 Easy interface... commit 9881f5516d24da521b701befc999b190770fa5a3 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:35:55 2012 +0100 Easy interface... commit 5a0b4197be4aff87ff13532b1aad723a8536d129 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:35:23 2012 +0100 Easy interface... commit e4bce00912811bc1638ebe1a4f5d91b61b615f7c Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:34:47 2012 +0100 Easy interface... commit 0872374b18ad5634550226579a6d483e2bcb7a12 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:33:56 2012 +0100 Easy interface... commit fa075c61c663c9fd4514df22fcd4a58c2c44ca0a Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:31:58 2012 +0100 Easy interface... commit 221f9cd044ce97464fca93332f1e679e2058d1cf Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:30:12 2012 +0100 Easy interface... commit ec2b858a82b50d8cd93b053152de8719d44b6da0 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:29:32 2012 +0100 Easy interface... commit 4159c7318162d58d6a658b6e2bd154289a75f5d8 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:29:17 2012 +0100 Easy interface... commit e040c00436ff5592478e9e08c2f7cd65d0ab7c3d Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:28:35 2012 +0100 Easy interface... commit a34b05154ca7195fa221bbd13bb49ce988fb2996 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:27:39 2012 +0100 Easy interface... commit f9b46f112b96e0ed075e9c2a4eddeaff8d0cd782 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:26:37 2012 +0100 Easy interface... commit d049b2f822cf81cbca670769f993ab81f624247e Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:26:24 2012 +0100 Easy interface... commit 8ff31ce1f38c3649728095b0702ee0313618e785 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:25:39 2012 +0100 Easy interface... commit 004a580c6b11cf08b7e370ade0b10a0a2e49d75f Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:25:12 2012 +0100 Easy interface... commit 29d1070b98cfd201af2298e4eb85ce562d00311a Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:23:57 2012 +0100 Easy interface... commit 158f5db9046a9ff9c3259ea836c6c476b25c9c49 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:23:40 2012 +0100 Easy interface... commit 9f761ff51b53913b21fbde30a652d21064840361 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:21:27 2012 +0100 Easy interface... commit 795c6464ca8be977ad1cdfad44c5cc7b427d30c5 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:19:08 2012 +0100 Easy interface... commit 64f60cddad9eefec5819d20c4f021c3608b2a822 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:18:32 2012 +0100 Easy interface... commit d0c595ea84d21e9ac947fc24d5620e20fb307840 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:18:23 2012 +0100 Easy interface... commit 4a593ce313848da9921c3b33cbf3d0cf5f713799 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:17:59 2012 +0100 Easy interface... commit a1552478a0f765fdef516643586c1950f8ba217f Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:15:54 2012 +0100 Easy interface... commit ac2184dee39db2fbcc0aee73da04116dd6bd93d5 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:14:57 2012 +0100 Easy interface... commit 393cbe4bf0eea270e37b8a2ecd78b71152272461 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:14:31 2012 +0100 Easy interface... commit a56995ac8aef7caf10a184acb93b7755b2b541f0 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:13:55 2012 +0100 Easy interface... commit 921d7d6740f4c774bbaed220c0ab109f43ee8849 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:07:57 2012 +0100 Easy interface... commit fe7de39d75e238f5f674c21ecec39f487d941907 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 14:04:36 2012 +0100 Easy interface... commit e6e158dd4343e4d75d385ae0861dc1df131a1c42 Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 13:59:29 2012 +0100 Easy interface... commit 9bb88f95d4cb42a393077b578fe697916a638f0d Author: ooxi <85fcd0ef4ec8@f977375cdcd6.anonbox.net> Date: Thu Nov 1 13:59:01 2012 +0100 Easy interface... --- CMakeLists.txt | 2 +- src/xml.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++- src/xml.h | 25 +++++++++++ test/test-xml.c | 53 +++++++++++++++++++++++ 4 files changed, 190 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47678b3..77ff54c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ PROJECT(xml) SET(VERSION_MAJOR "0") SET(VERSION_MINOR "1") -SET(VERSION_PATCH "2") +SET(VERSION_PATCH "3") CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR) diff --git a/src/xml.c b/src/xml.c index 59cca48..ee13669 100644 --- a/src/xml.c +++ b/src/xml.c @@ -22,6 +22,7 @@ */ #include #include +#include #include #include #include @@ -37,7 +38,7 @@ * UTF-8 text */ struct xml_string { - uint8_t* buffer; + uint8_t const* buffer; size_t length; }; @@ -59,7 +60,11 @@ struct xml_node { * An xml_document simply contains the root node and the underlying buffer */ struct xml_document { - struct xml_string buffer; + struct { + uint8_t* buffer; + size_t length; + } buffer; + struct xml_node* root; }; @@ -134,6 +139,20 @@ static _Bool xml_string_equals(struct xml_string* a, struct xml_string* b) { +/** + * [PRIVATE] + */ +static uint8_t* xml_string_clone(struct xml_string* s) { + uint8_t* clone = calloc(s->length + 1, sizeof(uint8_t)); + + xml_string_copy(s, clone, s->length); + clone[s->length] = 0; + + return clone; +} + + + /** * [PRIVATE] * @@ -715,6 +734,96 @@ struct xml_node* xml_node_child(struct xml_node* node, size_t child) { +/** + * [PUBLIC API] + */ +struct xml_node* xml_easy_child(struct xml_node* node, uint8_t const* child_name, ...) { + + /* Find childrens, one by one + */ + struct xml_node* current = node; + + va_list arguments; + va_start(arguments, child_name); + + + /* Descent to current.child + */ + while (child_name) { + + /* Convert child_name to xml_string for easy comparison + */ + struct xml_string cn = { + .buffer = child_name, + .length = strlen(child_name) + }; + + /* Interate through all children + */ + struct xml_node* next = 0; + + size_t i = 0; for (; i < xml_node_children(current); ++i) { + struct xml_node* child = xml_node_child(current, i); + + if (xml_string_equals(xml_node_name(child), &cn)) { + if (!next) { + next = child; + + /* Two children with the same name + */ + } else { + return 0; + } + } + } + + /* No child with that name found + */ + if (!next) { + return 0; + } + current = next; + + /* Find name of next child + */ + child_name = va_arg(arguments, uint8_t const*); + } + va_end(arguments); + + + /* Return current element + */ + return current; +} + + + +/** + * [PUBLIC API] + */ +uint8_t* xml_easy_name(struct xml_node* node) { + if (!node) { + return 0; + } + + return xml_string_clone(xml_node_name(node)); +} + + + +/** + * [PUBLIC API] + */ +uint8_t* xml_easy_content(struct xml_node* node) { + if (!node) { + return 0; + } + + return xml_string_clone(xml_node_content(node)); +} + + + /** * [PUBLIC API] */ diff --git a/src/xml.h b/src/xml.h index 448056e..39643ee 100644 --- a/src/xml.h +++ b/src/xml.h @@ -107,6 +107,31 @@ struct xml_node* xml_node_child(struct xml_node* node, size_t child); +/** + * @return The node described by the path or 0 if child cannot be found + * @warning Each element on the way must be unique + * @warning Last argument must be 0 + */ +struct xml_node* xml_easy_child(struct xml_node* node, uint8_t const* child, ...); + + + +/** + * @return 0-terminated copy of node name + * @warning User must free the result + */ +uint8_t* xml_easy_name(struct xml_node* node); + + + +/** + * @return 0-terminated copy of node content + * @warning User must free the result + */ +uint8_t* xml_easy_content(struct xml_node* node); + + + /** * @return Length of the string */ diff --git a/test/test-xml.c b/test/test-xml.c index de08c6d..6c0479a 100644 --- a/test/test-xml.c +++ b/test/test-xml.c @@ -141,6 +141,58 @@ static void test_xml_parse_document_1() { +/** + * Tests the eas functionality + */ +static void test_xml_parse_document_2() { + SOURCE(source, "" + "\n" + "\t\n" + "\t\tFirst content\n" + "\t\n" + "\t\n" + "Content A\n" + "Content B\n" + "\t\n" + "\t\n" + "\t\tSecond content\n" + "\t\n" + "\n" + ); + struct xml_document* document = xml_parse_document(source, strlen(source)); + assert_that(document, "Could not parse document"); + + struct xml_node* root = xml_document_root(document); + assert_that(string_equals(xml_node_name(root), "Parent"), "root node name must be `Parent'"); + assert_that(3 == xml_node_children(root), "root must have two children"); + + struct xml_node* test_a = xml_easy_child(root, "This", "Is", "A", "Test", 0); + assert_that(test_a, "Cannot find Parent/This/Is/A/Test"); + assert_that(string_equals(xml_node_content(test_a), "Content A"), "Content of Parent/This/Is/A/Test must be `Content A'"); + + struct xml_node* test_b = xml_easy_child(root, "This", "Is", "B", "Test", 0); + assert_that(test_b, "Cannot find Parent/This/Is/B/Test"); + assert_that(string_equals(xml_node_content(test_b), "Content B"), "Content of Parent/This/Is/B/Test must be `Content B'"); + + struct xml_node* test_c = xml_easy_child(root, "This", "Is", "C", "Test", 0); + assert_that(!test_c, "Must not find Parent/This/Is/C/Test because no such path exists"); + + struct xml_node* must_be_null = xml_easy_child(root, "Child"); + assert_that(!must_be_null, "Parent/Child cannot be a valid expression, because there are two children named `Child' in `Parent'"); + + uint8_t* name_is = xml_easy_name(xml_easy_child(root, "This", "Is", 0)); + assert_that(!strcmp(name_is, "Is"), "Name of Parent/This/Is must be `Is'"); + free(name_is); + + uint8_t* content_a = xml_easy_content(test_a); + assert_that(!strcmp(content_a, "Content A"), "Content of Parent/This/Is/A/Test must be `Content A'"); + free(content_a); + + xml_document_free(document, true); +} + + + /** @@ -149,6 +201,7 @@ static void test_xml_parse_document_1() { int main(int argc, char** argv) { test_xml_parse_document_0(); test_xml_parse_document_1(); + test_xml_parse_document_2(); fprintf(stdout, "All tests passed :-)\n"); exit(EXIT_SUCCESS);