241 lines
6.3 KiB
C
241 lines
6.3 KiB
C
/* 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;
|
|
}
|
|
|