#define LABWC_XML_H
#include <libxml/tree.h>
+#include <stdbool.h>
/*
* Converts dotted attributes into nested nodes.
*/
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 */
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");
}
#include <stdbool.h>
#include <strings.h>
#include "common/xml.h"
+#include "common/parse-bool.h"
/*
* Converts an attribute A.B.C="X" into <C><B><A>X</A></B></C>
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;
+}
'../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,
],
)