1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2010 Andreas Hofmeister <andi@collax.com>
4  *               2010 Vincent Bernat <bernat@luffy.cx>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "writer.h"
24 #include "../log.h"
25 
26 #define SEP '.'
27 
28 struct kv_writer_private {
29 	FILE *	fh;
30 	char *  prefix;
31 };
32 
33 void
kv_start(struct writer * w,const char * tag,const char * descr)34 kv_start(struct writer *w , const char *tag, const char *descr)
35 {
36 	struct kv_writer_private *p = w->priv;
37 	char *newprefix;
38 	int s;
39 
40 	s = strlen(p->prefix) + 1 + strlen(tag);
41 	if ((newprefix = malloc(s+1)) == NULL)
42 		fatal(NULL, NULL);
43 	if (strlen(p->prefix) > 0)
44 		snprintf(newprefix, s+1, "%s\1%s", p->prefix, tag);
45 	else
46 		snprintf(newprefix, s+1, "%s", tag);
47 	free(p->prefix);
48 	p->prefix = newprefix;
49 }
50 
51 void
kv_data(struct writer * w,const char * data)52 kv_data(struct writer *w, const char *data)
53 {
54 	struct kv_writer_private *p = w->priv;
55 	char *key = strdup(p->prefix);
56 	char *value = data?strdup(data):NULL;
57 	char *dot, *nl;
58 	if (!key) fatal(NULL, NULL);
59 	while ((dot = strchr(key, '\1')) != NULL)
60 		*dot = SEP;
61 	if (value) {
62 		nl = value;
63 		while ((nl = strchr(nl, '\n'))) {
64 			*nl = ' ';
65 			nl++;
66 		}
67 	}
68 	fprintf(p->fh, "%s=%s\n", key, value?value:"");
69 	free(key);
70 	free(value);
71 }
72 
73 void
kv_end(struct writer * w)74 kv_end(struct writer *w)
75 {
76 	struct kv_writer_private *p = w->priv;
77 	char *dot;
78 
79 	if ((dot = strrchr(p->prefix, '\1')) == NULL) {
80 		p->prefix[0] = '\0';
81 		fflush(p->fh);
82 	} else
83 		*dot = '\0';
84 }
85 
86 void
kv_attr(struct writer * w,const char * tag,const char * descr,const char * value)87 kv_attr(struct writer *w, const char *tag, const char *descr, const char *value)
88 {
89 	if (!strcmp(tag, "name") || !strcmp(tag, "type")) {
90 		/* Special case for name, replace the last prefix */
91 		kv_end(w);
92 		kv_start(w, value, NULL);
93 	} else {
94 		kv_start(w, tag, NULL);
95 		kv_data(w, value);
96 		kv_end(w);
97 	}
98 }
99 
100 void
kv_finish(struct writer * w)101 kv_finish(struct writer *w)
102 {
103 	struct kv_writer_private *p = w->priv;
104 
105 	free(p->prefix);
106 	free(w->priv);
107 	w->priv = NULL;
108 
109 	free(w);
110 }
111 
112 struct writer *
kv_init(FILE * fh)113 kv_init(FILE *fh)
114 {
115 
116 	struct writer *result;
117 	struct kv_writer_private *priv;
118 
119 	if ((priv = malloc(sizeof(*priv))) == NULL)
120 		fatal(NULL, NULL);
121 
122 	priv->fh = fh;
123 	priv->prefix = strdup("");
124 
125 	if ((result = malloc(sizeof(struct writer))) == NULL)
126 		fatal(NULL, NULL);
127 
128 	result->priv  = priv;
129 	result->start = kv_start;
130 	result->attr  = kv_attr;
131 	result->data  = kv_data;
132 	result->end   = kv_end;
133 	result->finish= kv_finish;
134 
135 	return result;
136 }
137