
Contents of /Public_Parser_JSON2-0.8/json_render.c:
// vim:syntax=c
#include "pike_types.h"
#include "stralloc.h"
#include "mapping.h"
#include "object.h"
#include "builtin_functions.h"
#include "version.h"
#define FLAG_UTF8 1
#define FLAG_HUMAN 2
#define FLAG_BEAUTY 3
void low_append_substr(struct string_builder *s, struct pike_string *str, int a, int b) {
if (b >= str->len && a <= b && a >= 0) {
Pike_error("Index out of bounds.\n");
}
if (a == b) {
string_builder_putchar(s, index_shared_string(str, a));
return;
}
#if VERSION_MAJOR >= 7 && VERSION_MINOR >= 7
switch (str->size_shift) {
case 0:
string_builder_binary_strcat0(s, (p_wchar0*)str->str + a, b - a + 1);
case 1:
string_builder_binary_strcat1(s, (p_wchar1*)str->str + a, b - a + 1);
case 2:
string_builder_binary_strcat2(s, (p_wchar2*)str->str + a, b - a + 1);
default:
free_string_builder(s);
Pike_error("Illegal shift size in low_append_string().\n");
}
#else
string_builder_append(s, MKPCHARP_OFF(str->str, str->size_shift, a), b - a + 1);
#endif
}
#define APPEND do { if (mark < i) low_append_substr(s, str, mark, i-1); } while(0);
void low_escape_string_append(struct string_builder *s, struct pike_string *str, int flags) {
int i, mark;
mark = 0;
if (flags & FLAG_HUMAN) for (i = 0; i < str->len; i++) {
unsigned INT32 c = index_shared_string(str, i);
switch (c) {
case '"': APPEND; string_builder_strcat(s, "\\\""); mark = i+1; break;
case '\\': APPEND; string_builder_strcat(s, "\\\\"); mark = i+1; break;
// case '/': APPEND; string_builder_strcat(s, "\\/"); mark = i+1; break;
case '\b': APPEND; string_builder_strcat(s, "\\b"); mark = i+1; break;
case '\f': APPEND; string_builder_strcat(s, "\\f"); mark = i+1; break;
case '\n': APPEND; string_builder_strcat(s, "\\n"); mark = i+1; break;
case '\r': APPEND; string_builder_strcat(s, "\\r"); mark = i+1; break;
case '\t': APPEND; string_builder_strcat(s, "\\t"); mark = i+1; break;
}
} else for (i = 0; i < str->len; i++) {
unsigned INT32 c = index_shared_string(str, i);
if (c == '"' || c == '\\') {
APPEND;
string_builder_putchar(s, '\\');
string_builder_putchar(s, c);
mark = i+1;
}
}
if (mark != str->len) low_append_substr(s, str, mark, str->len - 1);
}
#define APPENDN(n, c) do { int _c; for (_c = 0; _c < n; _c++) string_builder_strcat(s, c); } while(0);
int json_low_render(struct string_builder *s, struct svalue *v, int flags, int level) {
if (level < 0) {
level = -level;
} else if (flags & FLAG_HUMAN) APPENDN(level, " ");
switch (v->type) {
case T_ARRAY: {
struct array *a = v->u.array;
INT32 i;
string_builder_putchar(s, '[');
if (flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
for (i = 0; i < a->size; i++) {
json_low_render(s, a->item + i, flags, level+1);
if (i != a->size-1) {
string_builder_putchar(s, ',');
}
if (flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
}
if (flags & FLAG_HUMAN) APPENDN(level, " ");
string_builder_putchar(s, ']');
break;
}
case T_MAPPING: {
struct mapping *m = v->u.mapping;
int first = 1;
struct keypair *k;
INT32 e;
string_builder_putchar(s, '{');
if (flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
NEW_MAPPING_LOOP(m->data) {
if (first) {
first = 0;
} else {
string_builder_putchar(s, ',');
if (flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
}
if (k->ind.type != T_STRING) {
Pike_error("JSON objects must have string keys.\n");
}
json_low_render(s, &k->ind, flags, level+1); // we cheat here
if (flags & FLAG_HUMAN) string_builder_putchar(s, ' ');
string_builder_putchar(s, ':');
if (flags & FLAG_HUMAN) string_builder_putchar(s, ' ');
json_low_render(s, &k->val, flags, -level-1);
}
if (flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
if (flags & FLAG_HUMAN) APPENDN(level, " ");
string_builder_putchar(s, '}');
break;
}
case T_OBJECT: {
ref_push_object(v->u.object);
o_cast(string_type_string, PIKE_T_STRING);
if (Pike_sp[-1].type != T_STRING) {
pop_stack();
Pike_error("Could not cast object to string.\n");
}
v = Pike_sp-1;
string_builder_shared_strcat(s, v->u.string);
pop_stack();
break;
}
case T_STRING:
string_builder_putchar(s, '"');
if (flags & FLAG_UTF8) {
#if PIKE_MAJOR_VERSION < 7 || PIKE_MINOR_VERSION < 7
// we have to check for non-unicode chars
// for pike versions older than 7.7
CHECK_UNICODE(v->u.string);
#endif
push_svalue(v);
f_string_to_utf8(1);
v = Pike_sp-1;
low_escape_string_append(s, v->u.string, flags);
pop_stack();
} else {
CHECK_UNICODE(v->u.string);
low_escape_string_append(s, v->u.string, flags);
}
string_builder_putchar(s, '"');
break;
case T_INT: {
#if PIKE_MAJOR_VERSION >= 7 && PIKE_MINOR_VERSION >= 7
string_builder_sprintf(s, "%d", v->u.integer);
#else
struct pike_string *str;
push_constant_text("%d");
push_svalue(v);
f_sprintf(2);
if (Pike_sp[-1].type != T_STRING) {
Pike_error("sprintf did not return a string.\n");
}
str = Pike_sp[-1].u.string;
string_builder_shared_strcat(s, str);
pop_stack();
#endif
break;
}
case T_FLOAT: {
#if PIKE_MAJOR_VERSION >= 7 && PIKE_MINOR_VERSION >= 7
string_builder_sprintf(s, "%f", v->u.float_number);
#else
struct pike_string *str;
push_constant_text("%f");
push_svalue(v);
f_sprintf(2);
if (Pike_sp[-1].type != T_STRING) {
Pike_error("sprintf did not return a string.\n");
}
str = Pike_sp[-1].u.string;
string_builder_shared_strcat(s, str);
pop_stack();
#endif
break;
}
case T_MULTISET:
Pike_error("Cannot render a multiset.\n");
case T_FUNCTION:
Pike_error("Cannot render a function.\n");
default:
Pike_error("Cannot render this.\n");
}
if (!level && flags & FLAG_HUMAN) string_builder_putchar(s, '\n');
return 1;
}