diff options
Diffstat (limited to 'src/client/kv_writer.c')
-rw-r--r-- | src/client/kv_writer.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/client/kv_writer.c b/src/client/kv_writer.c new file mode 100644 index 0000000..56c9a43 --- /dev/null +++ b/src/client/kv_writer.c @@ -0,0 +1,133 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2010 Andreas Hofmeister <andi@collax.com> + * 2010 Vincent Bernat <bernat@luffy.cx> + * + * 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> + +#include "writer.h" +#include "../log.h" + +#define SEP '.' + +struct kv_writer_private { + FILE *fh; + char *prefix; +}; + +static void +kv_start(struct writer *w, const char *tag, const char *descr) +{ + struct kv_writer_private *p = w->priv; + char *newprefix; + int s; + + s = strlen(p->prefix) + 1 + strlen(tag); + if ((newprefix = malloc(s + 1)) == NULL) fatal(NULL, NULL); + if (strlen(p->prefix) > 0) + snprintf(newprefix, s + 1, "%s\1%s", p->prefix, tag); + else + snprintf(newprefix, s + 1, "%s", tag); + free(p->prefix); + p->prefix = newprefix; +} + +static void +kv_data(struct writer *w, const char *data) +{ + struct kv_writer_private *p = w->priv; + char *key = strdup(p->prefix); + char *value = data ? strdup(data) : NULL; + char *dot, *nl; + if (!key) fatal(NULL, NULL); + while ((dot = strchr(key, '\1')) != NULL) + *dot = SEP; + if (value) { + nl = value; + while ((nl = strchr(nl, '\n'))) { + *nl = ' '; + nl++; + } + } + fprintf(p->fh, "%s=%s\n", key, value ? value : ""); + free(key); + free(value); +} + +static void +kv_end(struct writer *w) +{ + struct kv_writer_private *p = w->priv; + char *dot; + + if ((dot = strrchr(p->prefix, '\1')) == NULL) { + p->prefix[0] = '\0'; + fflush(p->fh); + } else + *dot = '\0'; +} + +static void +kv_attr(struct writer *w, const char *tag, const char *descr, const char *value) +{ + if (!strcmp(tag, "name") || !strcmp(tag, "type")) { + /* Special case for name, replace the last prefix */ + kv_end(w); + kv_start(w, value, NULL); + } else { + kv_start(w, tag, NULL); + kv_data(w, value); + kv_end(w); + } +} + +static void +kv_finish(struct writer *w) +{ + struct kv_writer_private *p = w->priv; + + free(p->prefix); + free(w->priv); + w->priv = NULL; + + free(w); +} + +struct writer * +kv_init(FILE *fh) +{ + + struct writer *result; + struct kv_writer_private *priv; + + if ((priv = malloc(sizeof(*priv))) == NULL) fatal(NULL, NULL); + + priv->fh = fh; + priv->prefix = strdup(""); + + if ((result = malloc(sizeof(struct writer))) == NULL) fatal(NULL, NULL); + + result->priv = priv; + result->start = kv_start; + result->attr = kv_attr; + result->data = kv_data; + result->end = kv_end; + result->finish = kv_finish; + + return result; +} |