add some json parsing code
This commit is contained in:
parent
fa726cd82b
commit
c6e4aa0702
14
lib/hcl-c.c
14
lib/hcl-c.c
@ -65,13 +65,6 @@ struct hcl_client_t
|
|||||||
unsigned int logmask;
|
unsigned int logmask;
|
||||||
} cfg;
|
} cfg;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_bch_t* ptr;
|
|
||||||
hcl_oow_t len;
|
|
||||||
hcl_oow_t capa;
|
|
||||||
} req;
|
|
||||||
|
|
||||||
hcl_client_state_t state;
|
hcl_client_state_t state;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -238,9 +231,11 @@ static HCL_INLINE hcl_ooch_t unescape (hcl_ooch_t c)
|
|||||||
* i don't know if n, r, f, t, v should be supported here */
|
* i don't know if n, r, f, t, v should be supported here */
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
case 'a': return '\a';
|
||||||
|
case 'b': return '\b';
|
||||||
|
case 'f': return '\f';
|
||||||
case 'n': return '\n';
|
case 'n': return '\n';
|
||||||
case 'r': return '\r';
|
case 'r': return '\r';
|
||||||
case 'f': return '\f';
|
|
||||||
case 't': return '\t';
|
case 't': return '\t';
|
||||||
case 'v': return '\v';
|
case 'v': return '\v';
|
||||||
default: return c;
|
default: return c;
|
||||||
@ -779,6 +774,9 @@ static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow
|
|||||||
*xlen = ptr - data;
|
*xlen = ptr - data;
|
||||||
return 0; /* feed more for incomplete sequence */
|
return 0; /* feed more for incomplete sequence */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uc = *ptr;
|
||||||
|
bcslen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += bcslen;
|
ptr += bcslen;
|
||||||
|
@ -50,8 +50,8 @@ typedef enum hcl_jsoner_trait_t hcl_jsoner_trait_t;
|
|||||||
enum hcl_jsoner_state_t
|
enum hcl_jsoner_state_t
|
||||||
{
|
{
|
||||||
HCL_JSON_STATE_START,
|
HCL_JSON_STATE_START,
|
||||||
HCL_JSON_STATE_ARRAY_STARTED,
|
HCL_JSON_STATE_IN_ARRAY,
|
||||||
HCL_JSON_STATE_OBJECT_STARTED,
|
HCL_JSON_STATE_IN_DIC,
|
||||||
|
|
||||||
HCL_JSON_STATE_IN_WORD_VALUE,
|
HCL_JSON_STATE_IN_WORD_VALUE,
|
||||||
HCL_JSON_STATE_IN_NUMERIC_VALUE,
|
HCL_JSON_STATE_IN_NUMERIC_VALUE,
|
||||||
|
321
lib/json.c
321
lib/json.c
@ -45,6 +45,24 @@ enum hcl_jsoner_reply_attr_type_t
|
|||||||
};
|
};
|
||||||
typedef enum hcl_jsoner_reply_attr_type_t hcl_jsoner_reply_attr_type_t;
|
typedef enum hcl_jsoner_reply_attr_type_t hcl_jsoner_reply_attr_type_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct hcl_jsoner_state_node_t hcl_jsoner_state_node_t;
|
||||||
|
struct hcl_jsoner_state_node_t
|
||||||
|
{
|
||||||
|
hcl_jsoner_state_t state;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
int escaped;
|
||||||
|
int digit_count;
|
||||||
|
hcl_ooch_t acc;
|
||||||
|
} qv;
|
||||||
|
} u;
|
||||||
|
hcl_jsoner_state_node_t* next;
|
||||||
|
};
|
||||||
|
|
||||||
struct hcl_jsoner_t
|
struct hcl_jsoner_t
|
||||||
{
|
{
|
||||||
hcl_mmgr_t* mmgr;
|
hcl_mmgr_t* mmgr;
|
||||||
@ -65,71 +83,15 @@ struct hcl_jsoner_t
|
|||||||
unsigned int logmask;
|
unsigned int logmask;
|
||||||
} cfg;
|
} cfg;
|
||||||
|
|
||||||
|
hcl_jsoner_state_node_t state_top;
|
||||||
|
hcl_jsoner_state_node_t* state_stack;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
hcl_bch_t* ptr;
|
hcl_ooch_t* ptr;
|
||||||
hcl_oow_t len;
|
hcl_oow_t len;
|
||||||
hcl_oow_t capa;
|
hcl_oow_t capa;
|
||||||
} req;
|
} tok;
|
||||||
|
|
||||||
hcl_jsoner_state_t state;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_ooch_t* ptr;
|
|
||||||
hcl_oow_t len;
|
|
||||||
hcl_oow_t capa;
|
|
||||||
} tok;
|
|
||||||
|
|
||||||
hcl_jsoner_reply_type_t type;
|
|
||||||
hcl_jsoner_reply_attr_type_t last_attr_type;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_ooch_t* ptr;
|
|
||||||
hcl_oow_t len;
|
|
||||||
hcl_oow_t capa;
|
|
||||||
} last_attr_key; /* the last attr key shown */
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_oow_t nsplen; /* length remembered when the white space was shown */
|
|
||||||
} reply_value_unquoted;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int escaped;
|
|
||||||
} reply_value_quoted;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_oow_t nsplen; /* length remembered when the white space was shown */
|
|
||||||
} attr_value_unquoted;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int escaped;
|
|
||||||
} attr_value_quoted;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
hcl_oow_t max;
|
|
||||||
hcl_oow_t tally;
|
|
||||||
} length_bounded_data;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int in_data_part;
|
|
||||||
int negated;
|
|
||||||
hcl_oow_t max; /* chunk length */
|
|
||||||
hcl_oow_t tally;
|
|
||||||
hcl_oow_t total;
|
|
||||||
hcl_oow_t clcount;
|
|
||||||
} chunked_data;
|
|
||||||
} u;
|
|
||||||
} rep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -185,33 +147,33 @@ static HCL_INLINE int is_digitchar (hcl_ooci_t c)
|
|||||||
return (c >= '0' && c <= '9');
|
return (c >= '0' && c <= '9');
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_reply_token (hcl_jsoner_t* json)
|
static void clear_token (hcl_jsoner_t* json)
|
||||||
{
|
{
|
||||||
json->rep.tok.len = 0;
|
json->tok.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_to_reply_token (hcl_jsoner_t* json, hcl_ooch_t ch)
|
static int add_char_to_token (hcl_jsoner_t* json, hcl_ooch_t ch)
|
||||||
{
|
{
|
||||||
if (json->rep.tok.len >= json->rep.tok.capa)
|
if (json->tok.len >= json->tok.capa)
|
||||||
{
|
{
|
||||||
hcl_ooch_t* tmp;
|
hcl_ooch_t* tmp;
|
||||||
hcl_oow_t newcapa;
|
hcl_oow_t newcapa;
|
||||||
|
|
||||||
newcapa = HCL_ALIGN_POW2(json->rep.tok.len + 1, HCL_JSON_TOKEN_NAME_ALIGN);
|
newcapa = HCL_ALIGN_POW2(json->tok.len + 1, HCL_JSON_TOKEN_NAME_ALIGN);
|
||||||
tmp = hcl_jsoner_reallocmem(json, json->rep.tok.ptr, newcapa * HCL_SIZEOF(*tmp));
|
tmp = hcl_jsoner_reallocmem(json, json->tok.ptr, newcapa * HCL_SIZEOF(*tmp));
|
||||||
if (!tmp) return -1;
|
if (!tmp) return -1;
|
||||||
|
|
||||||
json->rep.tok.capa = newcapa;
|
json->tok.capa = newcapa;
|
||||||
json->rep.tok.ptr = tmp;
|
json->tok.ptr = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
json->rep.tok.ptr[json->rep.tok.len++] = ch;
|
json->tok.ptr[json->tok.len++] = ch;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HCL_INLINE int is_token (hcl_jsoner_t* json, const hcl_bch_t* str)
|
static HCL_INLINE int is_token (hcl_jsoner_t* json, const hcl_bch_t* str)
|
||||||
{
|
{
|
||||||
return hcl_comp_oochars_bcstr(json->rep.tok.ptr, json->rep.tok.len, str) == 0;
|
return hcl_comp_oochars_bcstr(json->tok.ptr, json->tok.len, str) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HCL_INLINE int is_token_integer (hcl_jsoner_t* json, hcl_oow_t* value)
|
static HCL_INLINE int is_token_integer (hcl_jsoner_t* json, hcl_oow_t* value)
|
||||||
@ -219,12 +181,12 @@ static HCL_INLINE int is_token_integer (hcl_jsoner_t* json, hcl_oow_t* value)
|
|||||||
hcl_oow_t i;
|
hcl_oow_t i;
|
||||||
hcl_oow_t v = 0;
|
hcl_oow_t v = 0;
|
||||||
|
|
||||||
if (json->rep.tok.len <= 0) return 0;
|
if (json->tok.len <= 0) return 0;
|
||||||
|
|
||||||
for (i = 0; i < json->rep.tok.len; i++)
|
for (i = 0; i < json->tok.len; i++)
|
||||||
{
|
{
|
||||||
if (!is_digitchar(json->rep.tok.ptr[i])) return 0;
|
if (!is_digitchar(json->tok.ptr[i])) return 0;
|
||||||
v = v * 10 + (json->rep.tok.ptr[i] - '0');
|
v = v * 10 + (json->tok.ptr[i] - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = v;
|
*value = v;
|
||||||
@ -233,41 +195,158 @@ static HCL_INLINE int is_token_integer (hcl_jsoner_t* json, hcl_oow_t* value)
|
|||||||
|
|
||||||
static HCL_INLINE hcl_ooch_t unescape (hcl_ooch_t c)
|
static HCL_INLINE hcl_ooch_t unescape (hcl_ooch_t c)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
/* as of this writing, the server side only escapes \ and ".
|
|
||||||
* i don't know if n, r, f, t, v should be supported here */
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
case 'a': return '\a';
|
||||||
|
case 'b': return '\b';
|
||||||
|
case 'f': return '\f';
|
||||||
case 'n': return '\n';
|
case 'n': return '\n';
|
||||||
case 'r': return '\r';
|
case 'r': return '\r';
|
||||||
case 'f': return '\f';
|
|
||||||
case 't': return '\t';
|
case 't': return '\t';
|
||||||
case 'v': return '\v';
|
case 'v': return '\v';
|
||||||
default: return c;
|
default: return c;
|
||||||
}
|
}
|
||||||
#else
|
}
|
||||||
return c;
|
|
||||||
#endif
|
static int push_state (hcl_jsoner_t* json, hcl_jsoner_state_t state)
|
||||||
|
{
|
||||||
|
hcl_jsoner_state_node_t* ss;
|
||||||
|
|
||||||
|
ss = hcl_jsoner_callocmem(json, HCL_SIZEOF(*ss));
|
||||||
|
if (!ss) return -1;
|
||||||
|
|
||||||
|
ss->state = state;
|
||||||
|
ss->next = json->state_stack;
|
||||||
|
|
||||||
|
json->state_stack = ss;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pop_state (hcl_jsoner_t* json)
|
||||||
|
{
|
||||||
|
hcl_jsoner_state_node_t* ss;
|
||||||
|
|
||||||
|
ss = json->state_stack;
|
||||||
|
HCL_ASSERT (json->dummy_hcl, ss != HCL_NULL && ss != &json->state_top);
|
||||||
|
json->state_stack = ss->next;
|
||||||
|
|
||||||
|
/* TODO: don't free this. move it to the free list? */
|
||||||
|
hcl_jsoner_freemem (json, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pop_all_states (hcl_jsoner_t* json)
|
||||||
|
{
|
||||||
|
while (json->state_stack != &json->state_top) pop_state (json);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_quoted_value_char (hcl_jsoner_t* json, hcl_ooci_t c)
|
||||||
|
{
|
||||||
|
if (json->state_stack->u.qv.escaped >= 2)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.acc = json->state_stack->u.qv.acc * 16 + c - '0';
|
||||||
|
json->state_stack->u.qv.digit_count++;
|
||||||
|
if (json->state_stack->u.qv.digit_count >= json->state_stack->u.qv.escaped) goto add_qv_acc;
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.acc = json->state_stack->u.qv.acc * 16 + c - 'a' + 10;
|
||||||
|
json->state_stack->u.qv.digit_count++;
|
||||||
|
if (json->state_stack->u.qv.digit_count >= json->state_stack->u.qv.escaped) goto add_qv_acc;
|
||||||
|
}
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.acc = json->state_stack->u.qv.acc * 16 + c - 'A' + 10;
|
||||||
|
json->state_stack->u.qv.digit_count++;
|
||||||
|
if (json->state_stack->u.qv.digit_count >= json->state_stack->u.qv.escaped) goto add_qv_acc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add_qv_acc:
|
||||||
|
if (add_char_to_token(json, json->state_stack->u.qv.acc) <= -1) return -1;
|
||||||
|
json->state_stack->u.qv.escaped = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (json->state_stack->u.qv.escaped == 1)
|
||||||
|
{
|
||||||
|
if (c == 'x')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.escaped = 2;
|
||||||
|
json->state_stack->u.qv.digit_count = 0;
|
||||||
|
json->state_stack->u.qv.acc = 0;
|
||||||
|
}
|
||||||
|
else if (c == 'u')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.escaped = 4;
|
||||||
|
json->state_stack->u.qv.digit_count = 0;
|
||||||
|
json->state_stack->u.qv.acc = 0;
|
||||||
|
}
|
||||||
|
else if (c == 'U')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.escaped = 8;
|
||||||
|
json->state_stack->u.qv.digit_count = 0;
|
||||||
|
json->state_stack->u.qv.acc = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.escaped = 0;
|
||||||
|
if (add_char_to_token(json, unescape(c)) <= -1) return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
json->state_stack->u.qv.escaped = 1;
|
||||||
|
}
|
||||||
|
else if (c == '\"')
|
||||||
|
{
|
||||||
|
pop_state (json);
|
||||||
|
HCL_LOG2 (json->dummy_hcl, HCL_LOG_APP | HCL_LOG_FATAL, "[%.*js]\n", json->tok.len, json->tok.ptr);
|
||||||
|
/* TODO: call callback ARRAY_VALUE*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (add_char_to_token(json, c) <= -1) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_numeric_value_char (hcl_jsoner_t* json, hcl_ooci_t c)
|
||||||
|
{
|
||||||
|
/* TODO: */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
||||||
{
|
{
|
||||||
switch (json->state)
|
if (c == HCL_OOCI_EOF)
|
||||||
|
{
|
||||||
|
if (json->state_stack->state == HCL_JSON_STATE_START)
|
||||||
|
{
|
||||||
|
/* no input data */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcl_jsoner_seterrbfmt (json, HCL_EFINIS, "unexpected end of data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("handling [%c] %d\n", c, (int)nbytes);
|
||||||
|
switch (json->state_stack->state)
|
||||||
{
|
{
|
||||||
case HCL_JSON_STATE_START:
|
case HCL_JSON_STATE_START:
|
||||||
if (c == HCL_OOCI_EOF)
|
if (c == '[')
|
||||||
{
|
{
|
||||||
hcl_jsoner_seterrbfmt (json, HCL_EFINIS, "unexpected end before reply name");
|
if (push_state(json, HCL_JSON_STATE_IN_ARRAY) <= -1) return -1;
|
||||||
goto oops;
|
|
||||||
}
|
|
||||||
else if (c == '[')
|
|
||||||
{
|
|
||||||
json->state = HCL_JSON_STATE_ARRAY_STARTED;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (c == '{')
|
else if (c == '{')
|
||||||
{
|
{
|
||||||
json->state = HCL_JSON_STATE_OBJECT_STARTED;
|
if (push_state(json, HCL_JSON_STATE_IN_DIC) <= -1) return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (is_spacechar(c))
|
else if (is_spacechar(c))
|
||||||
@ -282,14 +361,15 @@ static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_JSON_STATE_ARRAY_STARTED:
|
case HCL_JSON_STATE_IN_ARRAY:
|
||||||
if (c == HCL_OOCI_EOF)
|
if (c == ']')
|
||||||
{
|
{
|
||||||
|
pop_state (json);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (c == ']')
|
else if (c == ',')
|
||||||
{
|
{
|
||||||
break;
|
/* TODO: handle this */
|
||||||
}
|
}
|
||||||
else if (is_spacechar(c))
|
else if (is_spacechar(c))
|
||||||
{
|
{
|
||||||
@ -297,7 +377,9 @@ static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
|||||||
}
|
}
|
||||||
else if (c == '\"')
|
else if (c == '\"')
|
||||||
{
|
{
|
||||||
json->state = HCL_JSON_STATE_IN_QUOTED_VALUE;
|
|
||||||
|
if (push_state(json, HCL_JSON_STATE_IN_QUOTED_VALUE) <= -1) return -1;
|
||||||
|
clear_token (json);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (is_alphachar(c) || is_digitchar(c))
|
else if (is_alphachar(c) || is_digitchar(c))
|
||||||
@ -306,18 +388,15 @@ static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hcl_jsoner_seterrbfmt (json, HCL_EINVAL, "not starting with [ or { - %jc", (hcl_ooch_t)c);
|
hcl_jsoner_seterrbfmt (json, HCL_EINVAL, "wrong character inside array - %jc", (hcl_ooch_t)c);
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_JSON_STATE_OBJECT_STARTED:
|
case HCL_JSON_STATE_IN_DIC:
|
||||||
if (c == HCL_OOCI_EOF)
|
if (c == '}')
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (c == '}')
|
|
||||||
{
|
{
|
||||||
|
pop_state (json);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (is_spacechar(c))
|
else if (is_spacechar(c))
|
||||||
@ -334,31 +413,24 @@ static int handle_char (hcl_jsoner_t* json, hcl_ooci_t c, hcl_oow_t nbytes)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hcl_jsoner_seterrbfmt (json, HCL_EINVAL, "not starting with [ or { - %jc", (hcl_ooch_t)c);
|
hcl_jsoner_seterrbfmt (json, HCL_EINVAL, "wrong character inside dictionary - %jc", (hcl_ooch_t)c);
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_JSON_STATE_IN_WORD_VALUE:
|
case HCL_JSON_STATE_IN_WORD_VALUE:
|
||||||
if (c == HCL_OOCI_EOF)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_JSON_STATE_IN_QUOTED_VALUE:
|
case HCL_JSON_STATE_IN_QUOTED_VALUE:
|
||||||
|
if (handle_quoted_value_char(json, c) <= -1) goto oops;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCL_JSON_STATE_IN_NUMERIC_VALUE:
|
case HCL_JSON_STATE_IN_NUMERIC_VALUE:
|
||||||
|
if (handle_numeric_value_char(json, c) <= -1) goto oops;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
hcl_jsoner_seterrbfmt (json, HCL_EINTERN, "internal error - must not be called for state %d", (int)json->state);
|
hcl_jsoner_seterrbfmt (json, HCL_EINTERN, "internal error - must not be called for state %d", (int)json->state_stack->state);
|
||||||
goto oops;
|
goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,6 +470,10 @@ static int feed_json_data (hcl_jsoner_t* json, const hcl_bch_t* data, hcl_oow_t
|
|||||||
*xlen = ptr - data;
|
*xlen = ptr - data;
|
||||||
return 0; /* feed more for incomplete sequence */
|
return 0; /* feed more for incomplete sequence */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* advance 1 byte without proper conversion */
|
||||||
|
uc = *ptr;
|
||||||
|
bcslen = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += bcslen;
|
ptr += bcslen;
|
||||||
@ -407,6 +483,8 @@ static int feed_json_data (hcl_jsoner_t* json, const hcl_bch_t* data, hcl_oow_t
|
|||||||
c = *ptr++;
|
c = *ptr++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* handle a signle character */
|
||||||
if (handle_char(json, c, bcslen) <= -1) goto oops;
|
if (handle_char(json, c, bcslen) <= -1) goto oops;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,13 +542,18 @@ hcl_jsoner_t* hcl_jsoner_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_jsoner_p
|
|||||||
hcl_setoption (json->dummy_hcl, HCL_LOG_MASK, &json->cfg.logmask);
|
hcl_setoption (json->dummy_hcl, HCL_LOG_MASK, &json->cfg.logmask);
|
||||||
hcl_setcmgr (json->dummy_hcl, json->cmgr);
|
hcl_setcmgr (json->dummy_hcl, json->cmgr);
|
||||||
|
|
||||||
|
|
||||||
|
json->state_top.state = HCL_JSON_STATE_START;
|
||||||
|
json->state_top.next = HCL_NULL;
|
||||||
|
json->state_stack = &json->state_top;
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hcl_jsoner_close (hcl_jsoner_t* json)
|
void hcl_jsoner_close (hcl_jsoner_t* json)
|
||||||
{
|
{
|
||||||
if (json->rep.tok.ptr) hcl_jsoner_freemem (json, json->rep.tok.ptr);
|
pop_all_states (json);
|
||||||
if (json->rep.last_attr_key.ptr) hcl_jsoner_freemem (json, json->rep.last_attr_key.ptr);
|
if (json->tok.ptr) hcl_jsoner_freemem (json, json->tok.ptr);
|
||||||
hcl_close (json->dummy_hcl);
|
hcl_close (json->dummy_hcl);
|
||||||
HCL_MMGR_FREE (json->mmgr, json);
|
HCL_MMGR_FREE (json->mmgr, json);
|
||||||
}
|
}
|
||||||
@ -644,13 +727,15 @@ void hcl_jsoner_freemem (hcl_jsoner_t* json, void* ptr)
|
|||||||
|
|
||||||
hcl_jsoner_state_t hcl_jsoner_getstate (hcl_jsoner_t* json)
|
hcl_jsoner_state_t hcl_jsoner_getstate (hcl_jsoner_t* json)
|
||||||
{
|
{
|
||||||
return json->state;
|
return json->state_stack->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hcl_jsoner_reset (hcl_jsoner_t* json)
|
void hcl_jsoner_reset (hcl_jsoner_t* json)
|
||||||
{
|
{
|
||||||
/* TODO: reset XXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxx */
|
/* TODO: reset XXXXXXXXXXXXXXXXXXXXXXXXXXXxxxxx */
|
||||||
json->state = HCL_JSON_STATE_START;
|
pop_all_states (json);
|
||||||
|
HCL_ASSERT (json->dummy_hcl, json->state_stack == &json->state_top);
|
||||||
|
json->state_stack->state = HCL_JSON_STATE_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hcl_jsoner_feed (hcl_jsoner_t* json, const void* ptr, hcl_oow_t len, hcl_oow_t* xlen)
|
int hcl_jsoner_feed (hcl_jsoner_t* json, const void* ptr, hcl_oow_t len, hcl_oow_t* xlen)
|
||||||
|
246
lib/main-j.c
246
lib/main-j.c
@ -1,7 +1,28 @@
|
|||||||
#include <hcl-json.h>
|
#include <hcl-json.h>
|
||||||
|
#include <hcl-utl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* ========================================================================= */
|
||||||
|
|
||||||
|
typedef struct jsoner_xtn_t jsoner_xtn_t;
|
||||||
|
struct jsoner_xtn_t
|
||||||
|
{
|
||||||
|
int logfd;
|
||||||
|
unsigned int logmask;
|
||||||
|
int logfd_istty;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
hcl_bch_t buf[4096];
|
||||||
|
hcl_oow_t len;
|
||||||
|
} logbuf;
|
||||||
|
};
|
||||||
|
/* ========================================================================= */
|
||||||
|
|
||||||
static void* sys_alloc (hcl_mmgr_t* mmgr, hcl_oow_t size)
|
static void* sys_alloc (hcl_mmgr_t* mmgr, hcl_oow_t size)
|
||||||
{
|
{
|
||||||
@ -26,15 +47,238 @@ static hcl_mmgr_t sys_mmgr =
|
|||||||
HCL_NULL
|
HCL_NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ========================================================================= */
|
||||||
|
|
||||||
|
static int write_all (int fd, const hcl_bch_t* ptr, hcl_oow_t len)
|
||||||
|
{
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
hcl_ooi_t wr;
|
||||||
|
|
||||||
|
wr = write(fd, ptr, len);
|
||||||
|
|
||||||
|
if (wr <= -1)
|
||||||
|
{
|
||||||
|
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN == EWOULDBLOCK)
|
||||||
|
if (errno == EAGAIN) continue;
|
||||||
|
#else
|
||||||
|
#if defined(EAGAIN)
|
||||||
|
if (errno == EAGAIN) continue;
|
||||||
|
#elif defined(EWOULDBLOCK)
|
||||||
|
if (errno == EWOULDBLOCK) continue;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(EINTR)
|
||||||
|
/* TODO: would this interfere with non-blocking nature of this VM? */
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += wr;
|
||||||
|
len -= wr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int write_log (hcl_jsoner_t* jsoner, int fd, const hcl_bch_t* ptr, hcl_oow_t len)
|
||||||
|
{
|
||||||
|
jsoner_xtn_t* xtn;
|
||||||
|
|
||||||
|
|
||||||
|
xtn = hcl_jsoner_getxtn(jsoner);
|
||||||
|
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
if (xtn->logbuf.len > 0)
|
||||||
|
{
|
||||||
|
hcl_oow_t rcapa, cplen;
|
||||||
|
|
||||||
|
rcapa = HCL_COUNTOF(xtn->logbuf.buf) - xtn->logbuf.len;
|
||||||
|
cplen = (len >= rcapa)? rcapa: len;
|
||||||
|
|
||||||
|
memcpy (&xtn->logbuf.buf[xtn->logbuf.len], ptr, cplen);
|
||||||
|
xtn->logbuf.len += cplen;
|
||||||
|
ptr += cplen;
|
||||||
|
len -= cplen;
|
||||||
|
|
||||||
|
if (xtn->logbuf.len >= HCL_COUNTOF(xtn->logbuf.buf))
|
||||||
|
{
|
||||||
|
write_all(fd, xtn->logbuf.buf, xtn->logbuf.len);
|
||||||
|
xtn->logbuf.len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcl_oow_t rcapa;
|
||||||
|
|
||||||
|
rcapa = HCL_COUNTOF(xtn->logbuf.buf);
|
||||||
|
if (len >= rcapa)
|
||||||
|
{
|
||||||
|
write_all (fd, ptr, rcapa);
|
||||||
|
ptr += rcapa;
|
||||||
|
len -= rcapa;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy (xtn->logbuf.buf, ptr, len);
|
||||||
|
xtn->logbuf.len += len;
|
||||||
|
ptr += len;
|
||||||
|
len -= len;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush_log (hcl_jsoner_t* jsoner, int fd)
|
||||||
|
{
|
||||||
|
jsoner_xtn_t* xtn;
|
||||||
|
xtn = hcl_jsoner_getxtn(jsoner);
|
||||||
|
if (xtn->logbuf.len > 0)
|
||||||
|
{
|
||||||
|
write_all (fd, xtn->logbuf.buf, xtn->logbuf.len);
|
||||||
|
xtn->logbuf.len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_write (hcl_jsoner_t* jsoner, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len)
|
||||||
|
{
|
||||||
|
hcl_bch_t buf[256];
|
||||||
|
hcl_oow_t ucslen, bcslen;
|
||||||
|
jsoner_xtn_t* xtn;
|
||||||
|
hcl_oow_t msgidx;
|
||||||
|
int n, logfd;
|
||||||
|
|
||||||
|
xtn = hcl_jsoner_getxtn(jsoner);
|
||||||
|
|
||||||
|
if (mask & HCL_LOG_STDERR)
|
||||||
|
{
|
||||||
|
/* the messages that go to STDERR don't get masked out */
|
||||||
|
logfd = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(xtn->logmask & mask & ~HCL_LOG_ALL_LEVELS)) return; /* check log types */
|
||||||
|
if (!(xtn->logmask & mask & ~HCL_LOG_ALL_TYPES)) return; /* check log levels */
|
||||||
|
|
||||||
|
if (mask & HCL_LOG_STDOUT) logfd = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logfd = xtn->logfd;
|
||||||
|
if (logfd <= -1) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: beautify the log message.
|
||||||
|
* do classification based on mask. */
|
||||||
|
if (!(mask & (HCL_LOG_STDOUT | HCL_LOG_STDERR)))
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
char ts[32];
|
||||||
|
size_t tslen;
|
||||||
|
struct tm tm, *tmp;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
|
||||||
|
tmp = localtime_r (&now, &tm);
|
||||||
|
#if defined(HAVE_STRFTIME_SMALL_Z)
|
||||||
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
|
||||||
|
#else
|
||||||
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
|
||||||
|
#endif
|
||||||
|
if (tslen == 0)
|
||||||
|
{
|
||||||
|
strcpy (ts, "0000-00-00 00:00:00 +0000");
|
||||||
|
tslen = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_log (jsoner, logfd, ts, tslen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logfd == xtn->logfd && xtn->logfd_istty)
|
||||||
|
{
|
||||||
|
if (mask & HCL_LOG_FATAL) write_log (jsoner, logfd, "\x1B[1;31m", 7);
|
||||||
|
else if (mask & HCL_LOG_ERROR) write_log (jsoner, logfd, "\x1B[1;32m", 7);
|
||||||
|
else if (mask & HCL_LOG_WARN) write_log (jsoner, logfd, "\x1B[1;33m", 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HCL_OOCH_IS_UCH)
|
||||||
|
msgidx = 0;
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
ucslen = len;
|
||||||
|
bcslen = HCL_COUNTOF(buf);
|
||||||
|
|
||||||
|
n = hcl_conv_oochars_to_bchars_with_cmgr(&msg[msgidx], &ucslen, buf, &bcslen, hcl_get_utf8_cmgr());
|
||||||
|
if (n == 0 || n == -2)
|
||||||
|
{
|
||||||
|
/* n = 0:
|
||||||
|
* converted all successfully
|
||||||
|
* n == -2:
|
||||||
|
* buffer not sufficient. not all got converted yet.
|
||||||
|
* write what have been converted this round. */
|
||||||
|
|
||||||
|
/*HCL_ASSERT (hcl, ucslen > 0); */ /* if this fails, the buffer size must be increased */
|
||||||
|
/*assert (ucslen > 0);*/
|
||||||
|
|
||||||
|
/* attempt to write all converted characters */
|
||||||
|
if (write_log(jsoner, logfd, buf, bcslen) <= -1) break;
|
||||||
|
|
||||||
|
if (n == 0) break;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msgidx += ucslen;
|
||||||
|
len -= ucslen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (n <= -1)
|
||||||
|
{
|
||||||
|
/* conversion error */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
write_log (jsoner, logfd, msg, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (logfd == xtn->logfd && xtn->logfd_istty)
|
||||||
|
{
|
||||||
|
if (mask & (HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN)) write_log (jsoner, logfd, "\x1B[0m", 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
flush_log (jsoner, logfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================= */
|
||||||
|
|
||||||
int main (int argc, char* argv[])
|
int main (int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
hcl_jsoner_t* jsoner;
|
hcl_jsoner_t* jsoner;
|
||||||
|
hcl_jsoner_prim_t json_prim;
|
||||||
|
jsoner_xtn_t* jsoner_xtn;
|
||||||
|
hcl_oow_t xlen;
|
||||||
|
const char* p;
|
||||||
|
|
||||||
|
memset (&json_prim, 0, HCL_SIZEOF(json_prim));
|
||||||
|
json_prim.log_write = log_write;
|
||||||
|
|
||||||
|
jsoner = hcl_jsoner_open (&sys_mmgr, HCL_SIZEOF(jsoner_xtn_t), &json_prim, NULL);
|
||||||
|
|
||||||
|
|
||||||
jsoner = hcl_jsoner_open (&mmgr, 0, NULL, NULL);
|
jsoner_xtn = hcl_jsoner_getxtn(jsoner);
|
||||||
|
jsoner_xtn->logmask = HCL_LOG_ALL_LEVELS | HCL_LOG_ALL_TYPES;
|
||||||
|
|
||||||
|
p = "[ \"ab\\xab\\uC88B\\uC544\\uC6A9c\", \"kaden\", \"iron\" ]";
|
||||||
|
|
||||||
|
|
||||||
|
hcl_jsoner_feed (jsoner, p, strlen(p), &xlen);
|
||||||
hcl_jsoner_close (jsoner);
|
hcl_jsoner_close (jsoner);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -649,13 +649,13 @@ static int get_string (hcl_t* hcl, hcl_ooch_t end_char, hcl_ooch_t esc_char, int
|
|||||||
|
|
||||||
if (escaped == 1)
|
if (escaped == 1)
|
||||||
{
|
{
|
||||||
if (c == 'n') c = '\n';
|
if (c == 'a') c = '\a';
|
||||||
|
else if (c == 'b') c = '\b';
|
||||||
|
else if (c == 'f') c = '\f';
|
||||||
|
else if (c == 'n') c = '\n';
|
||||||
else if (c == 'r') c = '\r';
|
else if (c == 'r') c = '\r';
|
||||||
else if (c == 't') c = '\t';
|
else if (c == 't') c = '\t';
|
||||||
else if (c == 'f') c = '\f';
|
|
||||||
else if (c == 'b') c = '\b';
|
|
||||||
else if (c == 'v') c = '\v';
|
else if (c == 'v') c = '\v';
|
||||||
else if (c == 'a') c = '\a';
|
|
||||||
else if (c >= '0' && c <= '7' && !regex)
|
else if (c >= '0' && c <= '7' && !regex)
|
||||||
{
|
{
|
||||||
/* i don't support the octal notation for a regular expression.
|
/* i don't support the octal notation for a regular expression.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user