/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2010 Andreas Hofmeister * 2010 Vincent Bernat * * 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 #include #include #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; }