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