diff options
Diffstat (limited to 'src/client/xml_writer.c')
-rw-r--r-- | src/client/xml_writer.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/client/xml_writer.c b/src/client/xml_writer.c new file mode 100644 index 0000000..0c5efb5 --- /dev/null +++ b/src/client/xml_writer.c @@ -0,0 +1,158 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2010 Andreas Hofmeister <andi@collax.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +#include "writer.h" +#include "../log.h" + +struct xml_writer_private { + FILE *fh; + ssize_t depth; + xmlTextWriterPtr xw; + xmlDocPtr doc; +}; + +static void +xml_new_writer(struct xml_writer_private *priv) +{ + priv->xw = xmlNewTextWriterDoc(&(priv->doc), 0); + if (!priv->xw) fatalx("lldpctl", "cannot create xml writer"); + + xmlTextWriterSetIndent(priv->xw, 4); + + if (xmlTextWriterStartDocument(priv->xw, NULL, "UTF-8", NULL) < 0) + fatalx("lldpctl", "cannot start xml document"); +} + +static void +xml_start(struct writer *w, const char *tag, const char *descr) +{ + struct xml_writer_private *p = w->priv; + + if (p->depth == 0) xml_new_writer(p); + + if (xmlTextWriterStartElement(p->xw, BAD_CAST tag) < 0) + log_warnx("lldpctl", "cannot start '%s' element", tag); + + if (descr && (strlen(descr) > 0)) { + if (xmlTextWriterWriteFormatAttribute(p->xw, BAD_CAST "label", "%s", + descr) < 0) + log_warnx("lldpctl", + "cannot add attribute 'label' to element %s", tag); + } + + p->depth++; +} + +static void +xml_attr(struct writer *w, const char *tag, const char *descr, const char *value) +{ + struct xml_writer_private *p = w->priv; + + if (xmlTextWriterWriteFormatAttribute(p->xw, BAD_CAST tag, "%s", + value ? value : "") < 0) + log_warnx("lldpctl", "cannot add attribute %s with value %s", tag, + value ? value : "(none)"); +} + +static void +xml_data(struct writer *w, const char *data) +{ + struct xml_writer_private *p = w->priv; + if (xmlTextWriterWriteString(p->xw, BAD_CAST(data ? data : "")) < 0) + log_warnx("lldpctl", "cannot add '%s' as data to element", + data ? data : "(none)"); +} + +static void +xml_end(struct writer *w) +{ + struct xml_writer_private *p = w->priv; + + if (xmlTextWriterEndElement(p->xw) < 0) + log_warnx("lldpctl", "cannot end element"); + + if (--p->depth == 0) { + int failed = 0; + + if (xmlTextWriterEndDocument(p->xw) < 0) { + log_warnx("lldpctl", "cannot finish document"); + failed = 1; + } + + xmlFreeTextWriter(p->xw); + if (!failed) { + xmlDocDump(p->fh, p->doc); + fflush(p->fh); + } + xmlFreeDoc(p->doc); + } +} + +static void +xml_finish(struct writer *w) +{ + struct xml_writer_private *p = w->priv; + if (p->depth != 0) { + log_warnx("lldpctl", "unbalanced tags"); + /* memory leak... */ + } + + free(p); + free(w); +} + +struct writer * +xml_init(FILE *fh) +{ + + struct writer *result; + struct xml_writer_private *priv; + + priv = malloc(sizeof(*priv)); + if (!priv) { + fatalx("lldpctl", "out of memory"); + return NULL; + } + priv->fh = fh; + priv->depth = 0; + + result = malloc(sizeof(struct writer)); + if (!result) fatalx("lldpctl", "out of memory"); + + result->priv = priv; + result->start = xml_start; + result->attr = xml_attr; + result->data = xml_data; + result->end = xml_end; + result->finish = xml_finish; + + return result; +} |