/* 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; }