Add a config_writer API based on libxml2
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 21 Jan 2014 19:24:54 +0000 (14:24 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Thu, 6 Mar 2014 20:15:16 +0000 (15:15 -0500)
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Signed-off-by: David Goulet <dgoulet@efficios.com>
src/common/config/Makefile.am
src/common/config/config-internal.h [new file with mode: 0644]
src/common/config/config.c
src/common/config/config.h

index 057c137128a741c356cc777509fe3d99576b913d..0bde30e4d4e37129a07f50e19bace66798071cf5 100644 (file)
@@ -3,3 +3,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src
 noinst_LTLIBRARIES = libconfig.la
 
 libconfig_la_SOURCES = ini.c ini.h config.c config.h
+libconfig_la_CPPFLAGS = $(XML_CPPFLAGS)
+libconfig_la_LIBADD = $(XML_LIBS)
diff --git a/src/common/config/config-internal.h b/src/common/config/config-internal.h
new file mode 100644 (file)
index 0000000..ff3e629
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <libxml/xmlwriter.h>
+#include <stdio.h>
+
+struct config_writer {
+       xmlTextWriterPtr writer;
+};
index e945a19fb94c9f940b4113d8aa188b6fd5150ffe..18baf6bd5626c3c05bb620876b7d66ce195eb5bb 100644 (file)
 
 #define _GNU_SOURCE
 #include <assert.h>
-#include <config.h>
 #include <ctype.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <inttypes.h>
 
 #include <common/defaults.h>
 #include <common/error.h>
@@ -30,6 +29,7 @@
 #include <common/utils.h>
 
 #include "config.h"
+#include "config-internal.h"
 
 struct handler_filter_args {
        const char* section;
@@ -43,6 +43,12 @@ const char * const config_str_on = "on";
 const char * const config_str_no = "no";
 const char * const config_str_false = "false";
 const char * const config_str_off = "off";
+const char * const config_xml_encoding = "UTF-8";
+/* Size of the encoding's largest character */
+const size_t config_xml_encoding_bytes_per_char = 2;
+const char * const config_xml_indent_string = "\t";
+const char * const config_xml_true = "true";
+const char * const config_xml_false = "false";
 
 static int config_entry_handler_filter(struct handler_filter_args *args,
                const char *section, const char *name, const char *value)
@@ -171,3 +177,243 @@ int config_parse_value(const char *value)
 end:
        return ret;
 }
+
+/*
+ * Returns a xmlChar string which must be released using xmlFree().
+ */
+static xmlChar *encode_string(const char *in_str)
+{
+       xmlChar *out_str = NULL;
+       xmlCharEncodingHandlerPtr handler;
+       int out_len, ret, in_len;
+
+       assert(in_str);
+
+       handler = xmlFindCharEncodingHandler(config_xml_encoding);
+       if (!handler) {
+               ERR("xmlFindCharEncodingHandler return NULL!. Configure issue!");
+               goto end;
+       }
+
+       in_len = strlen(in_str);
+       /*
+        * Add 1 byte for the NULL terminted character. The factor 2 here is
+        * because UTF-8 can be on two bytes so this fits the worst case for each
+        * bytes.
+        */
+       out_len = (in_len * 2) + 1;
+       out_str = xmlMalloc(out_len);
+       if (!out_str) {
+               goto end;
+       }
+
+       ret = handler->input(out_str, &out_len, (const xmlChar *) in_str, &in_len);
+       if (ret < 0) {
+               xmlFree(out_str);
+               out_str = NULL;
+               goto end;
+       }
+
+       /* out_len is now the size of out_str */
+       out_str[out_len] = '\0';
+end:
+       return out_str;
+}
+
+LTTNG_HIDDEN
+struct config_writer *config_writer_create(int fd_output)
+{
+       int ret;
+       struct config_writer *writer;
+       xmlOutputBufferPtr buffer;
+
+       writer = zmalloc(sizeof(struct config_writer));
+       if (!writer) {
+               PERROR("zmalloc config_writer_create");
+               goto end;
+       }
+
+       buffer = xmlOutputBufferCreateFd(fd_output, NULL);
+       if (!buffer) {
+               goto error_destroy;
+       }
+
+       writer->writer = xmlNewTextWriter(buffer);
+       ret = xmlTextWriterStartDocument(writer->writer, NULL,
+               config_xml_encoding, NULL);
+       if (ret < 0) {
+               goto error_destroy;
+       }
+
+       ret = xmlTextWriterSetIndentString(writer->writer,
+               BAD_CAST config_xml_indent_string);
+       if (ret)  {
+               goto error_destroy;
+       }
+
+       ret = xmlTextWriterSetIndent(writer->writer, 1);
+       if (ret)  {
+               goto error_destroy;
+       }
+
+end:
+       return writer;
+error_destroy:
+       config_writer_destroy(writer);
+       return NULL;
+}
+
+LTTNG_HIDDEN
+int config_writer_destroy(struct config_writer *writer)
+{
+       int ret = 0;
+
+       if (!writer) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       if (xmlTextWriterEndDocument(writer->writer) < 0) {
+               WARN("Could not close XML document");
+               ret = -EIO;
+       }
+
+       if (writer->writer) {
+               xmlFreeTextWriter(writer->writer);
+       }
+
+       free(writer);
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_open_element(struct config_writer *writer,
+       const char *element_name)
+{
+       int ret;
+       xmlChar *encoded_element_name;
+
+       if (!writer || !writer->writer || !element_name || !element_name[0]) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_element_name = encode_string(element_name);
+       if (!encoded_element_name) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterStartElement(writer->writer, encoded_element_name);
+       xmlFree(encoded_element_name);
+end:
+       return ret > 0 ? 0 : ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_close_element(struct config_writer *writer)
+{
+       int ret;
+
+       if (!writer || !writer->writer) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterEndElement(writer->writer);
+end:
+       return ret > 0 ? 0 : ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_write_element_unsigned_int(struct config_writer *writer,
+               const char *element_name, uint64_t value)
+{
+       int ret;
+       xmlChar *encoded_element_name;
+
+       if (!writer || !writer->writer || !element_name || !element_name[0]) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_element_name = encode_string(element_name);
+       if (!encoded_element_name) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterWriteFormatElement(writer->writer,
+               encoded_element_name, "%" PRIu64, value);
+       xmlFree(encoded_element_name);
+end:
+       return ret > 0 ? 0 : ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_write_element_signed_int(struct config_writer *writer,
+               const char *element_name, int64_t value)
+{
+       int ret;
+       xmlChar *encoded_element_name;
+
+       if (!writer || !writer->writer || !element_name || !element_name[0]) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_element_name = encode_string(element_name);
+       if (!encoded_element_name) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterWriteFormatElement(writer->writer,
+               encoded_element_name, "%" PRIi64, value);
+       xmlFree(encoded_element_name);
+end:
+       return ret > 0 ? 0 : ret;
+}
+
+LTTNG_HIDDEN
+int config_writer_write_element_bool(struct config_writer *writer,
+               const char *element_name, int value)
+{
+       return config_writer_write_element_string(writer, element_name,
+               value ? config_xml_true : config_xml_false);
+}
+
+LTTNG_HIDDEN
+int config_writer_write_element_string(struct config_writer *writer,
+               const char *element_name, const char *value)
+{
+       int ret;
+       xmlChar *encoded_element_name = NULL;
+       xmlChar *encoded_value = NULL;
+
+       if (!writer || !writer->writer || !element_name || !element_name[0] ||
+               !value) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_element_name = encode_string(element_name);
+       if (!encoded_element_name) {
+               ret = -1;
+               goto end;
+       }
+
+       encoded_value = encode_string(value);
+       if (!encoded_value) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = xmlTextWriterWriteElement(writer->writer, encoded_element_name,
+               encoded_value);
+end:
+       xmlFree(encoded_element_name);
+       xmlFree(encoded_value);
+       return ret > 0 ? 0 : ret;
+}
index 73e39fc326cafbaadf2e427c86b3ff355d82df18..f5ca42485d371887eb86ed59460ff9e765b26b1b 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <common/config/ini.h>
 #include <common/macros.h>
+#include <stdint.h>
 
 struct config_entry {
        /* section is NULL if the entry is not in a section */
@@ -28,6 +29,9 @@ struct config_entry {
        const char *value;
 };
 
+/* Instance of a configuration writer. */
+struct config_writer;
+
 /*
  * A config_entry_handler_cb receives config_entry structures belonging to the
  * sections the handler has been registered to.
@@ -70,4 +74,115 @@ int config_get_section_entries(const char *path, const char *section,
 LTTNG_HIDDEN
 int config_parse_value(const char *value);
 
+/*
+ * Create an instance of a configuration writer.
+ *
+ * fd_output File to which the XML content must be written. The file will be
+ * closed once the config_writer has been destroyed.
+ *
+ * Returns an instance of a configuration writer on success, NULL on
+ * error.
+ */
+LTTNG_HIDDEN
+struct config_writer *config_writer_create(int fd_output);
+
+/*
+ * Destroy an instance of a configuration writer.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * Returns zero if the XML document could be closed cleanly. Negative values
+ * indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_destroy(struct config_writer *writer);
+
+/*
+ * Open an element tag.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * element_name Element tag name.
+ *
+ * Returns zero if the XML document could be closed cleanly.
+ * Negative values indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_open_element(struct config_writer *writer,
+               const char *element_name);
+
+/*
+ * Close the current element tag.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * Returns zero if the XML document could be closed cleanly.
+ * Negative values indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_close_element(struct config_writer *writer);
+
+/*
+ * Write an element of type unsigned int.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * element_name Element name.
+ *
+ * value Unsigned int value of the element
+ *
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_write_element_unsigned_int(struct config_writer *writer,
+               const char *element_name, uint64_t value);
+
+/*
+ * Write an element of type signed int.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * element_name Element name.
+ *
+ * value Signed int value of the element
+ *
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */LTTNG_HIDDEN
+int config_writer_write_element_signed_int(struct config_writer *writer,
+               const char *element_name, int64_t value);
+
+/*
+ * Write an element of type boolean.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * element_name Element name.
+ *
+ * value Boolean value of the element
+ *
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_write_element_bool(struct config_writer *writer,
+               const char *element_name, int value);
+
+/*
+ * Write an element of type string.
+ *
+ * writer An instance of a configuration writer.
+ *
+ * element_name Element name.
+ *
+ * value String value of the element
+ *
+ * Returns zero if the element's value could be written.
+ * Negative values indicate an error.
+ */
+LTTNG_HIDDEN
+int config_writer_write_element_string(struct config_writer *writer,
+               const char *element_name, const char *value);
+
 #endif /* _CONFIG_H */
This page took 0.030305 seconds and 4 git commands to generate.