diff --git a/mio/bin/t03.c b/mio/bin/t03.c index 3408007..0e2faa2 100644 --- a/mio/bin/t03.c +++ b/mio/bin/t03.c @@ -28,7 +28,7 @@ #include #include #include - +#include static int on_json_inst (mio_json_t* json, mio_json_inst_t inst, mio_oow_t level, const mio_oocs_t* str) { @@ -91,13 +91,15 @@ static int on_json_inst (mio_json_t* json, mio_json_inst_t inst, mio_oow_t level return 0; } +static int write_json_element (mio_jsonwr_t* jsonwr, const mio_bch_t* dptr, mio_oow_t dlen) +{ + write (1, dptr, dlen); + return 0; +} + int main (int argc, char* argv[]) { mio_t* mio = MIO_NULL; - mio_json_t* json = MIO_NULL; - char buf[128]; - mio_oow_t rem; - mio = mio_open(MIO_NULL, 0, MIO_NULL, 512, MIO_NULL); if (!mio) @@ -106,30 +108,73 @@ int main (int argc, char* argv[]) return -1; } - json = mio_json_open(mio, 0); - - mio_json_setinstcb (json, on_json_inst); - - - rem = 0; - while (1) { - int x; - size_t size = fread(&buf[rem], 1, sizeof(buf) - rem, stdin); - if (size <= 0) break; + mio_json_t* json = MIO_NULL; + char buf[128]; + mio_oow_t rem; + + json = mio_json_open(mio, 0); + + mio_json_setinstcb (json, on_json_inst); - if ((x = mio_json_feed(json, buf, size + rem, &rem, 1)) <= -1) + rem = 0; + while (1) { - printf ("**** ERROR ****\n"); - break; + int x; + size_t size = fread(&buf[rem], 1, sizeof(buf) - rem, stdin); + if (size <= 0) break; + + + if ((x = mio_json_feed(json, buf, size + rem, &rem, 1)) <= -1) + { + printf ("**** ERROR ****\n"); + break; + } + + //printf ("--> x %d input %d left-over %d\n", (int)x, (int)size, (int)rem); + if (rem > 0) memcpy (buf, &buf[size - rem], rem); } - //printf ("--> x %d input %d left-over %d\n", (int)x, (int)size, (int)rem); - if (rem > 0) memcpy (buf, &buf[size - rem], rem); + mio_json_close (json); + } + + + { + mio_jsonwr_t* jsonwr = MIO_NULL; + mio_uch_t ddd[4] = { 'D', '\0', 'R', 'Q' }; + mio_uch_t ddv[5] = { L'밝', L'혀', L'졌', L'는', L'데' }; + + jsonwr = mio_jsonwr_open (mio, 0); + + mio_jsonwr_setwritecb (jsonwr, write_json_element); + + mio_jsonwr_write (jsonwr, MIO_JSON_INST_START_ARRAY, 0, MIO_NULL, 0); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "hello", 5); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "world", 5); + + mio_jsonwr_write (jsonwr, MIO_JSON_INST_START_DIC, 0, MIO_NULL, 0); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_KEY, 0, "abc", 3); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "computer", 8); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_KEY, 0, "k", 1); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "play nice", 9); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_KEY, 1, ddd, 4); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 1, ddv, 5); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_END_DIC, 0, MIO_NULL, 0); + + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "tyler", 5); + + mio_jsonwr_write (jsonwr, MIO_JSON_INST_START_ARRAY, 0, MIO_NULL, 0); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "airplain", 8); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_STRING, 0, "gro\0wn\nup", 9); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_TRUE, 0, MIO_NULL, 0); + mio_jsonwr_write (jsonwr, MIO_JSON_INST_END_ARRAY, 0, MIO_NULL, 0); + + mio_jsonwr_write (jsonwr, MIO_JSON_INST_END_ARRAY, 0, MIO_NULL, 0); + + mio_jsonwr_close (jsonwr); } - mio_json_close (json); mio_close (mio); return 0; diff --git a/mio/lib/json.c b/mio/lib/json.c index 9401951..54dcfe4 100644 --- a/mio/lib/json.c +++ b/mio/lib/json.c @@ -26,11 +26,9 @@ #include #include +#include #include "mio-prv.h" -#include -#include - #define MIO_JSON_TOKEN_NAME_ALIGN 64 /* ========================================================================= */ @@ -101,7 +99,7 @@ static MIO_INLINE mio_ooch_t unescape (mio_ooch_t c) /* ========================================================================= */ -static int push_state (mio_json_t* json, mio_json_state_t state) +static int push_read_state (mio_json_t* json, mio_json_state_t state) { mio_json_state_node_t* ss; @@ -116,7 +114,7 @@ static int push_state (mio_json_t* json, mio_json_state_t state) return 0; } -static void pop_state (mio_json_t* json) +static void pop_read_state (mio_json_t* json) { mio_json_state_node_t* ss; @@ -137,9 +135,9 @@ static void pop_state (mio_json_t* json) mio_freemem (json->mio, ss); } -static void pop_all_states (mio_json_t* json) +static void pop_all_read_states (mio_json_t* json) { - while (json->state_stack != &json->state_top) pop_state (json); + while (json->state_stack != &json->state_top) pop_read_state (json); } /* ========================================================================= */ @@ -263,7 +261,7 @@ static int handle_string_value_char (mio_json_t* json, mio_ooci_t c) } else if (c == '\"') { - pop_state (json); + pop_read_state (json); if (invoke_data_inst(json, MIO_JSON_INST_STRING) <= -1) return -1; } else @@ -359,7 +357,7 @@ static int handle_character_value_char (mio_json_t* json, mio_ooci_t c) } else if (c == '\'') { - pop_state (json); + pop_read_state (json); if (json->tok.len < 1) { @@ -397,7 +395,7 @@ static int handle_numeric_value_char (mio_json_t* json, mio_ooci_t c) return 1; } - pop_state (json); + pop_read_state (json); MIO_ASSERT (json->mio, json->tok.len > 0); if (!mio_is_ooch_digit(json->tok.ptr[json->tok.len - 1])) @@ -419,7 +417,7 @@ static int handle_word_value_char (mio_json_t* json, mio_ooci_t c) return 1; } - pop_state (json); + pop_read_state (json); if (mio_comp_oochars_bcstr(json->tok.ptr, json->tok.len, "null", 0) == 0) inst = MIO_JSON_INST_NIL; else if (mio_comp_oochars_bcstr(json->tok.ptr, json->tok.len, "true", 0) == 0) inst = MIO_JSON_INST_TRUE; @@ -441,7 +439,7 @@ static int handle_start_char (mio_json_t* json, mio_ooci_t c) printf ("HANDLE START CHAR [%c]\n", c); if (c == '[') { - if (push_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; json->state_stack->u.ia.got_value = 0; if (json->instcb(json, MIO_JSON_INST_START_ARRAY, json->state_stack->level, MIO_NULL) <= -1) return -1; json->state_stack->level++; @@ -449,7 +447,7 @@ printf ("HANDLE START CHAR [%c]\n", c); } else if (c == '{') { - if (push_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; json->state_stack->u.id.state = 0; if (json->instcb(json, MIO_JSON_INST_START_DIC, json->state_stack->level, MIO_NULL) <= -1) return -1; json->state_stack->level++; @@ -475,7 +473,7 @@ static int handle_char_in_array (mio_json_t* json, mio_ooci_t c) if (c == ']') { if (json->instcb(json, MIO_JSON_INST_END_ARRAY, json->state_stack->level - 1, MIO_NULL) <= -1) return -1; - pop_state (json); + pop_read_state (json); return 1; } else if (c == ',') @@ -503,13 +501,13 @@ static int handle_char_in_array (mio_json_t* json, mio_ooci_t c) if (c == '\"') { - if (push_state(json, MIO_JSON_STATE_IN_STRING_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_STRING_VALUE) <= -1) return -1; clear_token (json); return 1; } else if (c == '\'') { - if (push_state(json, MIO_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1; clear_token (json); return 1; } @@ -517,20 +515,20 @@ static int handle_char_in_array (mio_json_t* json, mio_ooci_t c) */ else if (mio_is_ooch_digit(c) || c == '+' || c == '-') { - if (push_state(json, MIO_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1; clear_token (json); json->state_stack->u.nv.dotted = 0; return 0; /* start over */ } else if (mio_is_ooch_alpha(c)) { - if (push_state(json, MIO_JSON_STATE_IN_WORD_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_WORD_VALUE) <= -1) return -1; clear_token (json); return 0; /* start over */ } else if (c == '[') { - if (push_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; json->state_stack->u.ia.got_value = 0; if (json->instcb(json, MIO_JSON_INST_START_ARRAY, json->state_stack->level, MIO_NULL) <= -1) return -1; json->state_stack->level++; @@ -538,7 +536,7 @@ static int handle_char_in_array (mio_json_t* json, mio_ooci_t c) } else if (c == '{') { - if (push_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; json->state_stack->u.id.state = 0; if (json->instcb(json, MIO_JSON_INST_START_DIC, json->state_stack->level, MIO_NULL) <= -1) return -1; json->state_stack->level++; @@ -557,7 +555,7 @@ static int handle_char_in_dic (mio_json_t* json, mio_ooci_t c) if (c == '}') { if (json->instcb(json, MIO_JSON_INST_END_DIC, json->state_stack->level - 1, MIO_NULL) <= -1) return -1; - pop_state (json); + pop_read_state (json); return 1; } else if (c == ':') @@ -600,13 +598,13 @@ static int handle_char_in_dic (mio_json_t* json, mio_ooci_t c) if (c == '\"') { - if (push_state(json, MIO_JSON_STATE_IN_STRING_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_STRING_VALUE) <= -1) return -1; clear_token (json); return 1; } else if (c == '\'') { - if (push_state(json, MIO_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_CHARACTER_VALUE) <= -1) return -1; clear_token (json); return 1; } @@ -614,20 +612,20 @@ static int handle_char_in_dic (mio_json_t* json, mio_ooci_t c) */ else if (mio_is_ooch_digit(c) || c == '+' || c == '-') { - if (push_state(json, MIO_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_NUMERIC_VALUE) <= -1) return -1; clear_token (json); json->state_stack->u.nv.dotted = 0; return 0; /* start over */ } else if (mio_is_ooch_alpha(c)) { - if (push_state(json, MIO_JSON_STATE_IN_WORD_VALUE) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_WORD_VALUE) <= -1) return -1; clear_token (json); return 0; /* start over */ } else if (c == '[') { - if (push_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; json->state_stack->u.ia.got_value = 0; json->state_stack->level++; if (json->instcb(json, MIO_JSON_INST_START_ARRAY, json->state_stack->level, MIO_NULL) <= -1) return -1; @@ -635,7 +633,7 @@ static int handle_char_in_dic (mio_json_t* json, mio_ooci_t c) } else if (c == '{') { - if (push_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; + if (push_read_state(json, MIO_JSON_STATE_IN_DIC) <= -1) return -1; json->state_stack->u.id.state = 0; json->state_stack->level++; if (json->instcb(json, MIO_JSON_INST_START_DIC, json->state_stack->level, MIO_NULL) <= -1) return -1; @@ -826,7 +824,7 @@ int mio_json_init (mio_json_t* json, mio_t* mio) void mio_json_fini (mio_json_t* json) { - pop_all_states (json); + pop_all_read_states (json); if (json->tok.ptr) { mio_freemem (json->mio, json->tok.ptr); @@ -847,7 +845,7 @@ mio_json_state_t mio_json_getstate (mio_json_t* json) void mio_json_resetstates (mio_json_t* json) { - pop_all_states (json); + pop_all_read_states (json); MIO_ASSERT (json->mio, json->state_stack == &json->state_top); json->state_stack->state = MIO_JSON_STATE_START; } @@ -878,3 +876,394 @@ int mio_json_feed (mio_json_t* json, const void* ptr, mio_oow_t len, mio_oow_t* *rem = len - total; return 0; } + + +/* ========================================================================= */ + +static int push_write_state (mio_jsonwr_t* jsonwr, mio_json_state_t state) +{ + mio_jsonwr_state_node_t* ss; + + ss = (mio_jsonwr_state_node_t*)mio_callocmem(jsonwr->mio, MIO_SIZEOF(*ss)); + if (MIO_UNLIKELY(!ss)) return -1; + + ss->state = state; + ss->level = jsonwr->state_stack->level; /* copy from the parent */ + ss->next = jsonwr->state_stack; + + jsonwr->state_stack = ss; + return 0; +} + +static void pop_write_state (mio_jsonwr_t* jsonwr) +{ + mio_jsonwr_state_node_t* ss; + + ss = jsonwr->state_stack; + MIO_ASSERT (jsonwr->mio, ss != MIO_NULL && ss != &jsonwr->state_top); + jsonwr->state_stack = ss->next; + +/* TODO: don't free this. move it to the free list? */ + mio_freemem (jsonwr->mio, ss); +} + +static void pop_all_write_states (mio_jsonwr_t* jsonwr) +{ + while (jsonwr->state_stack != &jsonwr->state_top) pop_write_state (jsonwr); +} + +mio_jsonwr_t* mio_jsonwr_open (mio_t* mio, mio_oow_t xtnsize) +{ + mio_jsonwr_t* jsonwr; + + jsonwr = (mio_jsonwr_t*)mio_allocmem(mio, MIO_SIZEOF(*jsonwr) + xtnsize); + if (MIO_LIKELY(jsonwr)) + { + if (mio_jsonwr_init(jsonwr, mio) <= -1) + { + mio_freemem (mio, jsonwr); + return MIO_NULL; + } + else + { + MIO_MEMSET (jsonwr + 1, 0, xtnsize); + } + } + + return jsonwr; +} + +void mio_jsonwr_close (mio_jsonwr_t* jsonwr) +{ + mio_jsonwr_fini (jsonwr); + mio_freemem (jsonwr->mio, jsonwr); +} + +static int write_nothing (mio_jsonwr_t* jsonwr, const mio_bch_t* dptr, mio_oow_t dlen) +{ + return 0; +} + +int mio_jsonwr_init (mio_jsonwr_t* jsonwr, mio_t* mio) +{ + MIO_MEMSET (jsonwr, 0, MIO_SIZEOF(*jsonwr)); + + jsonwr->mio = mio; + jsonwr->writecb = write_nothing; + + jsonwr->state_top.state = MIO_JSON_STATE_START; + jsonwr->state_top.next = MIO_NULL; + jsonwr->state_stack = &jsonwr->state_top; + return 0; +} + +static int flush_wbuf (mio_jsonwr_t* jsonwr) +{ + int ret = 0; + + if (jsonwr->writecb(jsonwr, jsonwr->wbuf, jsonwr->wbuf_len) <= -1) ret = -1; + jsonwr->wbuf_len = 0; /* reset the buffer length regardless of writing result */ + + return ret; +} + +void mio_jsonwr_fini (mio_jsonwr_t* jsonwr) +{ + if (jsonwr->wbuf_len > 0) flush_wbuf (jsonwr); /* don't care about actual write failure */ + pop_all_write_states (jsonwr); +} + +/* ========================================================================= */ + +void mio_jsonwr_setwritecb (mio_jsonwr_t* jsonwr, mio_jsonwr_writecb_t writecb) +{ + jsonwr->writecb = writecb; +} + +static int escape_char (mio_uch_t uch, mio_uch_t* xch) +{ + int x = 1; + + switch (uch) + { + case '\"': + case '\\': + *xch = uch; + break; + + case '\b': + *xch = 'b'; + break; + + case '\f': + *xch = 'f'; + break; + + case '\n': + *xch = 'n'; + break; + + case '\r': + *xch = 'r'; + break; + + case '\t': + *xch = 't'; + break; + + default: + x = (uch >= 0 && uch <= 0x1f)? 2: 0; + break; + } + + return x; +} + +static int write_bytes_noesc (mio_jsonwr_t* jsonwr, const mio_bch_t* dptr, mio_oow_t dlen) +{ + mio_oow_t rem; + do + { + rem = MIO_COUNTOF(jsonwr->wbuf) - jsonwr->wbuf_len; + + if (dlen <= rem) + { + MIO_MEMCPY (&jsonwr->wbuf[jsonwr->wbuf_len], dptr, dlen); + jsonwr->wbuf_len += dlen; + if (dlen == rem && flush_wbuf(jsonwr) <= -1) return -1; + break; + } + + MIO_MEMCPY (&jsonwr->wbuf[jsonwr->wbuf_len], dptr, rem); + jsonwr->wbuf_len += rem; + dlen -= rem; + if (flush_wbuf(jsonwr) <= -1) return -1; + } + while (dlen > 0); + + return 0; +} + +static int write_bytes_esc (mio_jsonwr_t* jsonwr, const mio_bch_t* dptr, mio_oow_t dlen) +{ + const mio_bch_t* dend = dptr + dlen; + + while (dptr < dend) + { + int e; + mio_uch_t ec; + e = escape_char(*dptr, &ec); + if (e <= 0) + { + jsonwr->wbuf[jsonwr->wbuf_len++] = *dptr; + if (jsonwr->wbuf_len >= MIO_COUNTOF(jsonwr->wbuf) && flush_wbuf(jsonwr) <= -1) return -1; + } + else if (e == 1) + { + jsonwr->wbuf[jsonwr->wbuf_len++] = '\\'; + if (jsonwr->wbuf_len >= MIO_COUNTOF(jsonwr->wbuf) && flush_wbuf(jsonwr) <= -1) return -1; + jsonwr->wbuf[jsonwr->wbuf_len++] = ec; + if (jsonwr->wbuf_len >= MIO_COUNTOF(jsonwr->wbuf) && flush_wbuf(jsonwr) <= -1) return -1; + } + else + { + mio_bch_t bcsbuf[7]; + bcsbuf[0] = '\\'; + bcsbuf[1] = 'u'; + mio_fmt_uintmax_to_bcstr(&bcsbuf[2], 5, *dptr, 10, 4, '0', MIO_NULL); + if (write_bytes_noesc(jsonwr, bcsbuf, 6) <= -1) return -1; + } + + dptr++; + } + + return 0; +} + + +static int write_uchars (mio_jsonwr_t* jsonwr, int escape, const mio_uch_t* ptr, mio_oow_t len) +{ + mio_t* mio = mio_jsonwr_getmio(jsonwr); + const mio_uch_t* end = ptr + len; + mio_bch_t bcsbuf[MIO_BCSIZE_MAX + 4]; + mio_oow_t n; + + while (ptr < end) + { + if (escape) + { + int e; + mio_uch_t ec; + e = escape_char(*ptr, &ec); + if (e <= 0) goto no_escape; + else if (e == 1) + { + bcsbuf[0] = '\\'; + bcsbuf[1] = ec; + n = 2; + } + else + { + bcsbuf[0] = '\\'; + bcsbuf[1] = 'u'; + mio_fmt_uintmax_to_bcstr(&bcsbuf[2], 5, *ptr, 10, 4, '0', MIO_NULL); + n = 6; + } + } + else + { + no_escape: + n = mio->_cmgr->uctobc(*ptr, bcsbuf, MIO_COUNTOF(bcsbuf)); + if (n == 0) + { + mio_seterrnum (mio, MIO_EECERR); + return -1; + } + } + + ptr++; + if (write_bytes_noesc(jsonwr, bcsbuf, n) <= -1) return -1; + } + + return 0; +} + + +#define WRITE_BYTES_NOESC(jsonwr,dptr,dlen) do { if (write_bytes_noesc(jsonwr, dptr, dlen) <= -1) return -1; } while(0) +#define WRITE_BYTES_ESC(jsonwr,dptr,dlen) do { if (write_bytes_esc(jsonwr, dptr, dlen) <= -1) return -1; } while(0) + +#define WRITE_UCHARS(jsonwr,esc,dptr,dlen) do { if (write_uchars(jsonwr, esc, dptr, dlen) <= -1) return -1; } while(0) + +#define WRITE_LINE_BREAK(jsonwr) WRITE_BYTES_NOESC(jsonwr, "\n", 1) + +#define WRITE_COMMA(jsonwr) do { WRITE_BYTES_NOESC(jsonwr, ",", 1); if (jsonwr->pretty) WRITE_LINE_BREAK(jsonwr); } while(0) + +#define PREACTION_FOR_VLAUE(jsonwr,sn) do { \ + if (sn->state != MIO_JSON_STATE_IN_ARRAY && !(sn->state == MIO_JSON_STATE_IN_DIC && sn->dic_awaiting_val)) goto incompatible_inst; \ + if (sn->index > 0 && sn->state == MIO_JSON_STATE_IN_ARRAY) WRITE_COMMA (jsonwr); \ + sn->index++; \ + sn->dic_awaiting_val = 0; \ + if (jsonwr->pretty && sn->state == MIO_JSON_STATE_IN_ARRAY) WRITE_INDENT (jsonwr); \ +} while(0) + +#define WRITE_INDENT(jsonwr) do { mio_oow_t i; for (i = 0; i < jsonwr->state_stack->level; i++) WRITE_BYTES_NOESC (jsonwr, "\t", 1); } while(0) + +int mio_jsonwr_write (mio_jsonwr_t* jsonwr, mio_json_inst_t inst, int is_uchars, const void* dptr, mio_oow_t dlen) +{ + mio_jsonwr_state_node_t* sn = jsonwr->state_stack; + +jsonwr->pretty = 1; + switch (inst) + { + case MIO_JSON_INST_START_ARRAY: + if (sn->state != MIO_JSON_STATE_START && sn->state != MIO_JSON_STATE_IN_ARRAY && + !(sn->state == MIO_JSON_STATE_IN_DIC && sn->dic_awaiting_val)) goto incompatible_inst; + if (sn->index > 0) WRITE_COMMA (jsonwr); + sn->index++; + sn->dic_awaiting_val = 0; + if (jsonwr->pretty) WRITE_INDENT (jsonwr); + WRITE_BYTES_NOESC (jsonwr, "[", 1); + if (jsonwr->pretty) WRITE_LINE_BREAK (jsonwr); + if (push_write_state(jsonwr, MIO_JSON_STATE_IN_ARRAY) <= -1) return -1; + jsonwr->state_stack->level++; + break; + + case MIO_JSON_INST_START_DIC: + if (sn->state != MIO_JSON_STATE_START && sn->state != MIO_JSON_STATE_IN_ARRAY && + !(sn->state == MIO_JSON_STATE_IN_DIC && !sn->dic_awaiting_val)) goto incompatible_inst; + if (sn->index > 0) WRITE_COMMA (jsonwr); + sn->index++; + sn->dic_awaiting_val = 0; + if (jsonwr->pretty) WRITE_INDENT (jsonwr); + WRITE_BYTES_NOESC (jsonwr, "{", 1); + if (jsonwr->pretty) WRITE_LINE_BREAK (jsonwr); + if (push_write_state (jsonwr, MIO_JSON_STATE_IN_DIC) <= -1) return -1; + jsonwr->state_stack->level++; + break; + + case MIO_JSON_INST_END_ARRAY: + if (sn->state != MIO_JSON_STATE_IN_ARRAY) goto incompatible_inst; + pop_write_state (jsonwr); + if (jsonwr->pretty) + { + WRITE_LINE_BREAK (jsonwr); + WRITE_INDENT (jsonwr); + } + WRITE_BYTES_NOESC (jsonwr, "]", 1); + if (jsonwr->state_stack->state == MIO_JSON_STATE_START) + { + /* end of json */ + if (jsonwr->pretty) WRITE_LINE_BREAK (jsonwr); + if (jsonwr->wbuf_len > 0 && flush_wbuf(jsonwr) <= -1) return -1; + } + break; + + case MIO_JSON_INST_END_DIC: + if (sn->state != MIO_JSON_STATE_IN_DIC || sn->dic_awaiting_val) goto incompatible_inst; + pop_write_state (jsonwr); + if (jsonwr->pretty) + { + WRITE_LINE_BREAK (jsonwr); + WRITE_INDENT (jsonwr); + } + WRITE_BYTES_NOESC (jsonwr, "}", 1); + if (jsonwr->state_stack->state == MIO_JSON_STATE_START) + { + /* end of json */ + if (jsonwr->pretty) WRITE_LINE_BREAK (jsonwr); + if (jsonwr->wbuf_len > 0 && flush_wbuf(jsonwr) <= -1) return -1; + } + break; + + case MIO_JSON_INST_KEY: + if (sn->state != MIO_JSON_STATE_IN_DIC || sn->dic_awaiting_val) goto incompatible_inst; + if (sn->index > 0) WRITE_COMMA (jsonwr); + if (jsonwr->pretty) WRITE_INDENT (jsonwr); + WRITE_BYTES_NOESC (jsonwr, "\"", 1); + if (is_uchars) WRITE_UCHARS (jsonwr, 1, dptr, dlen); + else WRITE_BYTES_ESC (jsonwr, dptr, dlen); + WRITE_BYTES_NOESC (jsonwr, "\": ", 3); + sn->dic_awaiting_val = 1; + break; + + case MIO_JSON_INST_NIL: + PREACTION_FOR_VLAUE (jsonwr, sn); + WRITE_BYTES_NOESC (jsonwr, "nil", 3); + break; + + case MIO_JSON_INST_TRUE: + PREACTION_FOR_VLAUE (jsonwr, sn); + WRITE_BYTES_NOESC (jsonwr, "true", 4); + break; + + case MIO_JSON_INST_FALSE: + PREACTION_FOR_VLAUE (jsonwr, sn); + WRITE_BYTES_NOESC (jsonwr, "false", 5); + break; + + case MIO_JSON_INST_NUMBER: + case MIO_JSON_INST_CHARACTER: + PREACTION_FOR_VLAUE (jsonwr, sn); + if (is_uchars) + WRITE_UCHARS (jsonwr, 0, dptr, dlen); + else + WRITE_BYTES_NOESC (jsonwr, dptr, dlen); + break; + + case MIO_JSON_INST_STRING: + PREACTION_FOR_VLAUE (jsonwr, sn); + WRITE_BYTES_NOESC (jsonwr, "\"", 1); + if (is_uchars) WRITE_UCHARS (jsonwr, 1, dptr, dlen); + else WRITE_BYTES_ESC (jsonwr, dptr, dlen); + WRITE_BYTES_NOESC (jsonwr, "\"", 1); + break; + + default: + incompatible_inst: + flush_wbuf(jsonwr); + mio_seterrbfmt (jsonwr->mio, MIO_EINVAL, "incompatiable write instruction - %d", (int)inst); + return -1; + } + + return 0; +} diff --git a/mio/lib/mio-json.h b/mio/lib/mio-json.h index 4a117c0..d61e09f 100644 --- a/mio/lib/mio-json.h +++ b/mio/lib/mio-json.h @@ -131,6 +131,39 @@ struct mio_json_t /* ========================================================================= */ +typedef struct mio_jsonwr_t mio_jsonwr_t; + +typedef int (*mio_jsonwr_writecb_t) ( + mio_jsonwr_t* jsonwr, + /*mio_oow_t level,*/ + const mio_bch_t* dptr, + mio_oow_t dlen +); + +typedef struct mio_jsonwr_state_node_t mio_jsonwr_state_node_t; +struct mio_jsonwr_state_node_t +{ + mio_json_state_t state; + mio_oow_t level; + mio_oow_t index; + int dic_awaiting_val; + mio_jsonwr_state_node_t* next; +}; + +struct mio_jsonwr_t +{ + mio_t* mio; + mio_jsonwr_writecb_t writecb; + mio_jsonwr_state_node_t state_top; + mio_jsonwr_state_node_t* state_stack; + int pretty; + + mio_bch_t wbuf[4096]; + mio_oow_t wbuf_len; +}; + +/* ========================================================================= */ + #if defined(__cplusplus) extern "C" { #endif @@ -159,12 +192,17 @@ static MIO_INLINE mio_t* mio_json_getmio (mio_json_t* json) { return json->mio; # define mio_json_getmio(json) (((mio_json_t*)(json))->mio) #endif +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_json_getxtn (mio_json_t* json) { return (void*)(json + 1); } +#else +#define mio_json_getxtn(json) ((void*)((mio_json_t*)(json) + 1)) +#endif + MIO_EXPORT void mio_json_setinstcb ( mio_json_t* json, mio_json_instcb_t instcb ); - MIO_EXPORT mio_json_state_t mio_json_getstate ( mio_json_t* json ); @@ -195,13 +233,51 @@ MIO_EXPORT int mio_json_feed ( int stop_if_ever_completed ); +/* ========================================================================= */ + +MIO_EXPORT mio_jsonwr_t* mio_jsonwr_open ( + mio_t* mio, + mio_oow_t xtnsize +); + +MIO_EXPORT void mio_jsonwr_close ( + mio_jsonwr_t* jsonwr +); + +MIO_EXPORT int mio_jsonwr_init ( + mio_jsonwr_t* jsonwr, + mio_t* mio +); + +MIO_EXPORT void mio_jsonwr_fini ( + mio_jsonwr_t* jsonwr +); #if defined(MIO_HAVE_INLINE) -static MIO_INLINE void* mio_json_getxtn (mio_json_t* json) { return (void*)(json + 1); } +static MIO_INLINE mio_t* mio_jsonwr_getmio (mio_jsonwr_t* jsonwr) { return jsonwr->mio; } #else -#define mio_json_getxtn(json) ((void*)((mio_json_t*)(json) + 1)) +# define mio_jsonwr_getmio(jsonwr) (((mio_jsonwr_t*)(jsonwr))->mio) #endif +#if defined(MIO_HAVE_INLINE) +static MIO_INLINE void* mio_jsonwr_getxtn (mio_jsonwr_t* jsonwr) { return (void*)(jsonwr + 1); } +#else +#define mio_jsonwr_getxtn(jsonwr) ((void*)((mio_jsonwr_t*)(jsonwr) + 1)) +#endif + +MIO_EXPORT void mio_jsonwr_setwritecb ( + mio_jsonwr_t* jsonwr, + mio_jsonwr_writecb_t writecb +); + +MIO_EXPORT int mio_jsonwr_write ( + mio_jsonwr_t* jsonwr, + mio_json_inst_t inst, + int is_uchars, + const void* dptr, + mio_oow_t dlen +); + #if defined(__cplusplus) } #endif diff --git a/mio/lib/utl.c b/mio/lib/utl.c index 029d556..f1dd72a 100644 --- a/mio/lib/utl.c +++ b/mio/lib/utl.c @@ -1659,7 +1659,7 @@ MIO_INLINE int mio_conv_uchars_to_bchars_with_cmgr ( break; } - n = cmgr->uctobc (*p, bcs, rem); + n = cmgr->uctobc(*p, bcs, rem); if (n == 0) { ret = -1; @@ -1684,7 +1684,7 @@ MIO_INLINE int mio_conv_uchars_to_bchars_with_cmgr ( { mio_oow_t n; - n = cmgr->uctobc (*p, bcsbuf, MIO_COUNTOF(bcsbuf)); + n = cmgr->uctobc(*p, bcsbuf, MIO_COUNTOF(bcsbuf)); if (n == 0) { ret = -1;