diff --git a/include/common/xml.h b/include/common/xml.h index 7bc8eb26..3cfa5539 100644 --- a/include/common/xml.h +++ b/include/common/xml.h @@ -3,6 +3,7 @@ #define LABWC_XML_H #include +#include /* * Converts dotted attributes into nested nodes. @@ -26,4 +27,42 @@ */ void lab_xml_expand_dotted_attributes(xmlNode *root); +/* Returns true if the node only contains a string or is empty */ +bool lab_xml_node_is_leaf(xmlNode *node); + +bool lab_xml_get_node(xmlNode *node, const char *key, xmlNode **dst_node); +bool lab_xml_get_string(xmlNode *node, const char *key, char *s, size_t len); +bool lab_xml_get_int(xmlNode *node, const char *key, int *i); +bool lab_xml_get_bool(xmlNode *node, const char *key, bool *b); + +static inline xmlNode * +lab_xml_get_next_child(xmlNode *child) +{ + if (!child) { + return NULL; + } + do { + child = child->next; + } while (child && child->type != XML_ELEMENT_NODE); + + return child; +} + +static inline void +lab_xml_get_key_and_content(xmlNode *node, char **name, char **content) +{ + if (node) { + *name = (char *)node->name; + *content = (char *)xmlNodeGetContent(node); + } +} + +#define LAB_XML_FOR_EACH(parent, child, key, content) \ + for ((child) = (parent)->children, \ + lab_xml_get_key_and_content((child), &(key), &(content)); \ + (child); \ + xmlFree((xmlChar *)(content)), \ + (child) = lab_xml_get_next_child(child), \ + lab_xml_get_key_and_content((child), &(key), &(content))) + #endif /* LABWC_XML_H */ diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 6f835f22..f9e9d1d9 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -5532,6 +5532,7 @@ sub process { if ($starts_with_if_while_etc && !length($s) && $filename ne "include/view.h" && $filename ne "include/common/array.h" + && $filename ne "include/common/xml.h" && $filename ne "include/ssd-internal.h") { CHK("BRACES", "[labwc-custom] open brace { expected after if/while/for/switch - even with single statement blocks"); } diff --git a/src/common/xml.c b/src/common/xml.c index 08ec18b6..df8c26e4 100644 --- a/src/common/xml.c +++ b/src/common/xml.c @@ -4,6 +4,7 @@ #include #include #include "common/xml.h" +#include "common/parse-bool.h" /* * Converts an attribute A.B.C="X" into X @@ -129,3 +130,69 @@ lab_xml_expand_dotted_attributes(xmlNode *parent) lab_xml_expand_dotted_attributes(node); } } + +bool +lab_xml_node_is_leaf(xmlNode *node) +{ + if (node->type != XML_ELEMENT_NODE) { + return false; + } + for (xmlNode *child = node->children; child; child = child->next) { + if (child->type != XML_TEXT_NODE) { + return false; + } + } + return true; +} + +static bool +get_node(xmlNode *node, const char *key, xmlNode **dst_node, bool leaf_only) +{ + for (xmlNode *child = node->last; child; child = child->prev) { + if (child->type != XML_ELEMENT_NODE) { + continue; + } + if (leaf_only && !lab_xml_node_is_leaf(child)) { + continue; + } + if (!strcasecmp((char *)child->name, key)) { + *dst_node = child; + return true; + } + } + return false; +} + +bool +lab_xml_get_node(xmlNode *node, const char *key, xmlNode **dst_node) +{ + return get_node(node, key, dst_node, /* leaf_only */ false); +} + +bool +lab_xml_get_string(xmlNode *node, const char *key, char *s, size_t len) +{ + xmlNode *child; + if (get_node(node, key, &child, /* leaf_only */ true)) { + xmlChar *content = xmlNodeGetContent(child); + g_strlcpy(s, (char *)content, len); + xmlFree(content); + return true; + } + return false; +} + +bool +lab_xml_get_bool(xmlNode *node, const char *key, bool *b) +{ + xmlNode *child; + if (get_node(node, key, &child, /* leaf_only */ true)) { + char *s = (char *)xmlNodeGetContent(child); + int ret = parse_bool(s, -1); + if (ret >= 0) { + *b = ret; + return true; + } + } + return false; +} diff --git a/t/meson.build b/t/meson.build index 66534a2c..6aafc1e9 100644 --- a/t/meson.build +++ b/t/meson.build @@ -5,12 +5,14 @@ test_lib = static_library( '../src/common/mem.c', '../src/common/string-helpers.c', '../src/common/xml.c', + '../src/common/parse-bool.c', ), include_directories: [labwc_inc], dependencies: [ dep_cmocka, glib, xml2, + wlroots, ], )