blob: a59b3b0988d12605754018a24d89764e72ca8f6b [file] [log] [blame]
/* JSON Printer
* ZZJSON - Copyright (C) 2008 by Ivo van Poorten
* License: GNU Lesser General Public License version 2.1
*/
#include "zzjson.h"
#define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1;
//#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1;
#define PUTC(c) PRINT("%c",c)
#define INC 4
static int print_string(ZZJSON_CONFIG *config, char *s) {
int c, bs;
if (!s) return 0;
while ((c = *s++)) {
bs = 1;
switch (c) {
// case '/': // useless escape of forward slash
case '\\':
if (*s == 'u') bs = 0; // copy \uHHHH verbatim
break;
case '"': break;
case '\b': c = 'b'; break;
case '\f': c = 'f'; break;
case '\n': c = 'n'; break;
case '\r': c = 'r'; break;
case '\t': c = 't'; break;
default: bs = 0; break;
}
if (bs) PUTC('\\');
PUTC(c);
}
return 0;
}
static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson,
unsigned int indent, unsigned int objval) {
char c = 0, d = 0;
if (!zzjson) return -1;
switch(zzjson->type) {
case ZZJSON_OBJECT: c = '{'; d = '}'; break;
case ZZJSON_ARRAY: c = '['; d = ']'; break;
default: break;
}
if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c);
while (zzjson) {
switch(zzjson->type) {
case ZZJSON_OBJECT:
if (zzjson->value.object.val) {
PRINT("\n%*s\"", indent+INC, "");
if (print_string(config, zzjson->value.object.label) < 0)
return -1;
PRINT("\" :");
if (zzjson_print2(config, zzjson->value.object.val,
indent+INC, 1) < 0) return -1;
}
break;
case ZZJSON_ARRAY:
if (zzjson->value.array.val)
if (zzjson_print2(config, zzjson->value.array.val,
indent+INC, 0) < 0) return -1;
break;
case ZZJSON_STRING:
PRINT(objval ? " \"" : "\n%*s\"", indent, "");
if (print_string(config, zzjson->value.string.string)<0) return -1;
PUTC('"');
break;
case ZZJSON_FALSE:
PRINT(objval ? " false" : "\n%*sfalse", indent, "");
break;
case ZZJSON_NULL:
PRINT(objval ? " null" : "\n%*snull", indent, "");
break;
case ZZJSON_TRUE:
PRINT(objval ? " true" : "\n%*strue", indent, "");
break;
case ZZJSON_NUMBER_NEGINT:
case ZZJSON_NUMBER_POSINT:
case ZZJSON_NUMBER_DOUBLE:
PRINT(objval ? " " : "\n%*s", indent, "");
if (zzjson->type == ZZJSON_NUMBER_DOUBLE) {
PRINT("%16.16e", zzjson->value.number.val.dval);
} else {
if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-');
PRINT("%llu", zzjson->value.number.val.ival);
}
default:
break;
}
zzjson = zzjson->next;
if (zzjson) PUTC(',');
}
if (d) PRINT("\n%*s%c", indent, "", d);
return 0;
}
int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) {
int retval = zzjson_print2(config, zzjson, 0, 0);
// if (retval >= 0) retval = config->putchar('\n', config->ohandle);
#ifndef CONFIG_NO_ERROR_MESSAGES
if (retval < 0) config->error(config->ehandle, "print: unable to print");
#endif
return retval;
}