/* -*- 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;
};
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;
}
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);
}
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';
}
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);
}
}
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;
}