/* JSON Create ZZJSON structures
* ZZJSON - Copyright (C) 2008 by Ivo van Poorten
* License: GNU Lesser General Public License version 2.1
*/
#include "zzjson.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#ifdef CONFIG_NO_ERROR_MESSAGES
#define ERROR(x...)
#else
#define ERROR(x...) config->error(config->ehandle, ##x)
#endif
#define MEMERROR() ERROR("out of memory")
static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) {
ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON));
if (!zzjson) MEMERROR();
else zzjson->type = type;
return zzjson;
}
ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) {
return zzjson_create_templ(config, ZZJSON_TRUE);
}
ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) {
return zzjson_create_templ(config, ZZJSON_FALSE);
}
ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) {
return zzjson_create_templ(config, ZZJSON_NULL);
}
ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) {
ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE);
if (zzjson)
zzjson->value.number.val.dval = d;
return zzjson;
}
ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) {
ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT);
if (zzjson) {
zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
zzjson->value.number.val.ival = llabs(i);
}
return zzjson;
}
/* sdup mimics strdup, but avoids having another function pointer in config */
static char *sdup(ZZJSON_CONFIG *config, char *s) {
size_t slen = strlen(s)+1;
char *scopy = config->malloc(slen);
if (!scopy) MEMERROR();
else memcpy(scopy, s, slen);
return scopy;
}
ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) {
ZZJSON *zzjson = NULL;
char *scopy;
if (!(scopy = sdup(config,s))) return zzjson;
if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING)))
zzjson->value.string.string = scopy;
else
config->free(scopy);
return zzjson;
}
ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) {
ZZJSON *zzjson, *retval, *val;
va_list ap;
if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson;
retval = zzjson;
va_start(ap, config);
val = va_arg(ap, ZZJSON *);
while (val) {
zzjson->value.array.val = val;
val = va_arg(ap, ZZJSON *);
if (val) {
ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY);
if (!next) {
while (retval) {
next = retval->next;
config->free(retval);
retval = next;
}
break;
}
zzjson->next = next;
zzjson = next;
}
}
va_end(ap);
return retval;
}
ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) {
ZZJSON *zzjson, *retval, *val;
char *label, *labelcopy;
va_list ap;
if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson;
retval = zzjson;
va_start(ap, config);
label = va_arg(ap, char *);
while (label) {
val = va_arg(ap, ZZJSON *);
labelcopy = sdup(config, label);
if (!labelcopy) {
zzjson_free(config, retval);
retval = NULL;
break;
}
zzjson->value.object.label = labelcopy;
zzjson->value.object.val = val;
label = va_arg(ap, char *);
if (label) {
ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT);
if (!next) {
while (retval) {
next = retval->next;
config->free(retval->value.object.label);
config->free(retval);
retval = next;
}
break;
}
zzjson->next = next;
zzjson = next;
}
}
va_end(ap);
return retval;
}
ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array,
ZZJSON *val) {
ZZJSON *zzjson;
if (!array->value.array.val) { /* empty array */
array->value.array.val = val;
return array;
}
zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
if (zzjson) {
zzjson->value.array.val = val;
zzjson->next = array;
}
return zzjson;
}
ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array,
ZZJSON *val) {
ZZJSON *retval = array, *zzjson;
if (!array->value.array.val) { /* empty array */
array->value.array.val = val;
return array;
}
zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
if (!zzjson) return NULL;
while (array->next) array = array->next;
zzjson->value.array.val = val;
array->next = zzjson;
return retval;
}
ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object,
char *label, ZZJSON *val) {
ZZJSON *zzjson = NULL;
char *labelcopy = sdup(config, label);
if (!labelcopy) return zzjson;
if (!object->value.object.label) { /* empty object */
object->value.object.label = labelcopy;
object->value.object.val = val;
return object;
}
zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
if (zzjson) {
zzjson->value.object.label = labelcopy;
zzjson->value.object.val = val;
zzjson->next = object;
} else {
config->free(labelcopy);
}
return zzjson;
}
ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object,
char *label, ZZJSON *val) {
ZZJSON *retval = object, *zzjson = NULL;
char *labelcopy = sdup(config, label);
if (!labelcopy) return zzjson;
if (!object->value.object.label) { /* empty object */
object->value.object.label = labelcopy;
object->value.object.val = val;
return object;
}
zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
if (!zzjson) {
config->free(labelcopy);
return NULL;
}
while (object->next) object = object->next;
zzjson->value.object.label = labelcopy;
zzjson->value.object.val = val;
object->next = zzjson;
return retval;
}