1/* JSON Create ZZJSON structures
2 * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
3 * License: GNU Lesser General Public License version 2.1
4 */
5
6#include "zzjson.h"
7#include <stdlib.h>
8#include <string.h>
9#include <stdarg.h>
10
11#ifdef CONFIG_NO_ERROR_MESSAGES
12#define ERROR(x...)
13#else
14#define ERROR(x...)     config->error(config->ehandle, ##x)
15#endif
16#define MEMERROR()      ERROR("out of memory")
17
18static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) {
19    ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON));
20    if (!zzjson) MEMERROR();
21    else         zzjson->type = type;
22    return zzjson;
23}
24
25ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) {
26    return zzjson_create_templ(config, ZZJSON_TRUE);
27}
28
29ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) {
30    return zzjson_create_templ(config, ZZJSON_FALSE);
31}
32
33ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) {
34    return zzjson_create_templ(config, ZZJSON_NULL);
35}
36
37ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) {
38    ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE);
39    if (zzjson)
40        zzjson->value.number.val.dval = d;
41    return zzjson;
42}
43
44ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) {
45    ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT);
46    if (zzjson) {
47        zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
48        zzjson->value.number.val.ival = llabs(i);
49    }
50    return zzjson;
51}
52
53/* sdup mimics strdup, but avoids having another function pointer in config */
54static char *sdup(ZZJSON_CONFIG *config, char *s) {
55    size_t slen = strlen(s)+1;
56    char *scopy = config->malloc(slen);
57
58    if (!scopy) MEMERROR();
59    else        memcpy(scopy, s, slen);
60    return scopy;
61}
62
63ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) {
64    ZZJSON *zzjson = NULL;
65    char *scopy;
66
67    if (!(scopy = sdup(config,s))) return zzjson;
68
69    if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING)))
70        zzjson->value.string.string = scopy;
71    else
72        config->free(scopy);
73
74    return zzjson;
75}
76
77ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) {
78    ZZJSON *zzjson, *retval, *val;
79    va_list ap;
80
81    if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson;
82    retval = zzjson;
83
84    va_start(ap, config);
85    val = va_arg(ap, ZZJSON *);
86    while (val) {
87        zzjson->value.array.val = val;
88        val = va_arg(ap, ZZJSON *);
89
90        if (val) {
91            ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY);
92            if (!next) {
93                while (retval) {
94                    next = retval->next;
95                    config->free(retval);
96                    retval = next;
97                }
98                break;
99            }
100            zzjson->next = next;
101            zzjson = next;
102        }
103    }
104    va_end(ap);
105    return retval;
106}
107
108ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) {
109    ZZJSON *zzjson, *retval, *val;
110    char *label, *labelcopy;
111    va_list ap;
112
113    if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson;
114    retval = zzjson;
115
116    va_start(ap, config);
117    label = va_arg(ap, char *);
118    while (label) {
119        val = va_arg(ap, ZZJSON *);
120        labelcopy = sdup(config, label);
121
122        if (!labelcopy) {
123            zzjson_free(config, retval);
124            retval = NULL;
125            break;
126        }
127
128        zzjson->value.object.label  = labelcopy;
129        zzjson->value.object.val    = val;
130
131        label = va_arg(ap, char *);
132
133        if (label) {
134            ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT);
135            if (!next) {
136                while (retval) {
137                    next = retval->next;
138                    config->free(retval->value.object.label);
139                    config->free(retval);
140                    retval = next;
141                }
142                break;
143            }
144            zzjson->next = next;
145            zzjson = next;
146        }
147    }
148    va_end(ap);
149    return retval;
150}
151
152ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array,
153                                                    ZZJSON *val) {
154    ZZJSON *zzjson;
155
156    if (!array->value.array.val) { /* empty array */
157        array->value.array.val = val;
158        return array;
159    }
160
161    zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
162    if (zzjson) {
163        zzjson->value.array.val = val;
164        zzjson->next = array;
165    }
166    return zzjson;
167}
168
169ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array,
170                                                   ZZJSON *val) {
171    ZZJSON *retval = array, *zzjson;
172
173    if (!array->value.array.val) { /* empty array */
174        array->value.array.val = val;
175        return array;
176    }
177
178    zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
179    if (!zzjson) return NULL;
180
181    while (array->next) array = array->next;
182
183    zzjson->value.array.val = val;
184    array->next = zzjson;
185
186    return retval;
187}
188
189ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object,
190                              char *label, ZZJSON *val) {
191    ZZJSON *zzjson = NULL;
192    char *labelcopy = sdup(config, label);
193
194    if (!labelcopy) return zzjson;
195
196    if (!object->value.object.label) { /* empty object */
197        object->value.object.label  = labelcopy;
198        object->value.object.val    = val;
199        return object;
200    }
201
202    zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
203    if (zzjson) {
204        zzjson->value.object.label  = labelcopy;
205        zzjson->value.object.val    = val;
206        zzjson->next = object;
207    } else {
208        config->free(labelcopy);
209    }
210    return zzjson;
211}
212
213ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object,
214                             char *label, ZZJSON *val) {
215    ZZJSON *retval = object, *zzjson = NULL;
216    char *labelcopy = sdup(config, label);
217
218    if (!labelcopy) return zzjson;
219
220    if (!object->value.object.label) { /* empty object */
221        object->value.object.label  = labelcopy;
222        object->value.object.val    = val;
223        return object;
224    }
225
226    zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
227    if (!zzjson) {
228        config->free(labelcopy);
229        return NULL;
230    }
231
232    while (object->next) object = object->next;
233
234    zzjson->value.object.label  = labelcopy;
235    zzjson->value.object.val    = val;
236    object->next = zzjson;
237
238    return retval;
239}
240
241