|
|
@ -10,12 +10,18 @@ |
|
|
|
|
|
|
|
#define BIN_INC_SIZE 2048 |
|
|
|
|
|
|
|
#define COUNT_OF(x) (sizeof(x)/sizeof(x[0])) |
|
|
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) |
|
|
|
|
|
|
|
#define MAYBE_PRETTY_INDENT(e) ( e->pretty ? enc_shift(e) : 1 ) |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
ErlNifEnv* env; |
|
|
|
jiffy_st* atoms; |
|
|
|
int uescape; |
|
|
|
int pretty; |
|
|
|
|
|
|
|
int shiftcnt; |
|
|
|
int count; |
|
|
|
|
|
|
|
int iolen; |
|
|
@ -36,6 +42,8 @@ enc_init(Encoder* e, ErlNifEnv* env, ERL_NIF_TERM opts, ErlNifBinary* bin) |
|
|
|
e->env = env; |
|
|
|
e->atoms = enif_priv_data(env); |
|
|
|
e->uescape = 0; |
|
|
|
e->pretty = 0; |
|
|
|
e->shiftcnt = 0; |
|
|
|
e->count = 0; |
|
|
|
|
|
|
|
if(!enif_is_list(env, opts)) { |
|
|
@ -45,6 +53,8 @@ enc_init(Encoder* e, ErlNifEnv* env, ERL_NIF_TERM opts, ErlNifBinary* bin) |
|
|
|
while(enif_get_list_cell(env, opts, &val, &opts)) { |
|
|
|
if(enif_compare(val, e->atoms->atom_uescape) == 0) { |
|
|
|
e->uescape = 1; |
|
|
|
} else if(enif_compare(val, e->atoms->atom_pretty) == 0) { |
|
|
|
e->pretty = 1; |
|
|
|
} else { |
|
|
|
return 0; |
|
|
|
} |
|
|
@ -376,42 +386,83 @@ enc_char(Encoder* e, char c) |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
enc_shift(Encoder* e) { |
|
|
|
// Don't call this function directly. |
|
|
|
// Use macro MAYBE_PRETTY_INDENT(e). |
|
|
|
|
|
|
|
// Compile-time initialized array of indent strings. |
|
|
|
// Every string starts with its length. |
|
|
|
static char* shifts[] = { |
|
|
|
"\x01\n", |
|
|
|
"\x03\n ", |
|
|
|
"\x05\n ", |
|
|
|
"\x07\n ", |
|
|
|
"\x09\n ", |
|
|
|
"\x0b\n ", |
|
|
|
"\x0d\n ", |
|
|
|
"\x0f\n " |
|
|
|
}; |
|
|
|
|
|
|
|
int cnt = COUNT_OF(shifts) - 1; |
|
|
|
char *shift = shifts[ MIN(e->shiftcnt, cnt) ]; |
|
|
|
if (!enc_literal(e, shift + 1, *shift)) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
for (; cnt < e->shiftcnt; ++cnt) { |
|
|
|
if (!enc_literal(e, " ", 2)) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_start_object(Encoder* e) |
|
|
|
{ |
|
|
|
e->count++; |
|
|
|
return enc_char(e, '{'); |
|
|
|
e->shiftcnt++; |
|
|
|
return enc_char(e, '{') && MAYBE_PRETTY_INDENT(e); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_end_object(Encoder* e) |
|
|
|
{ |
|
|
|
return enc_char(e, '}'); |
|
|
|
if (!e->shiftcnt--) |
|
|
|
return 0; |
|
|
|
return MAYBE_PRETTY_INDENT(e) && enc_char(e, '}'); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_start_array(Encoder* e) |
|
|
|
{ |
|
|
|
e->count++; |
|
|
|
return enc_char(e, '['); |
|
|
|
e->shiftcnt++; |
|
|
|
return enc_char(e, '[') && MAYBE_PRETTY_INDENT(e); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_end_array(Encoder* e) |
|
|
|
{ |
|
|
|
return enc_char(e, ']'); |
|
|
|
if (!e->shiftcnt--) |
|
|
|
return 0; |
|
|
|
return MAYBE_PRETTY_INDENT(e) && enc_char(e, ']'); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_colon(Encoder* e) |
|
|
|
{ |
|
|
|
return enc_char(e, ':'); |
|
|
|
if (!e->pretty) |
|
|
|
return enc_char(e, ':'); |
|
|
|
return enc_literal(e, " : ", 3); |
|
|
|
} |
|
|
|
|
|
|
|
static inline int |
|
|
|
enc_comma(Encoder* e) |
|
|
|
{ |
|
|
|
return enc_char(e, ','); |
|
|
|
return enc_char(e, ',') && MAYBE_PRETTY_INDENT(e); |
|
|
|
} |
|
|
|
|
|
|
|
ERL_NIF_TERM |
|
|
|