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