1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-30 00:00:16 +01:00

lejp: object indexes

This adds an optional feature LEJP_FLAG_FEAT_OBJECT_INDEXES that changes
lejp to treat { } items as indexable in ctx->i[] / ctx->ipos, since they
also can take commas.

This may break existing uses so it requires the default-off feature flag to
enable it.  The flags context field is zeroed by lejp_construct(), so any
flags should be set on ctx->flags after alling that.

There's also a flag LEJP_FLAG_LATEST available as an alias to enable any
desirable but not-backwards-compatible behaviour, including this.

Add the info to the README and adapt the unit test to do it both with and
without the FEAT_OBJECT_INDEXES flag.
This commit is contained in:
Andy Green 2021-11-05 07:01:11 +00:00
parent 9734cadf11
commit c935df1e7e
4 changed files with 188 additions and 60 deletions

View file

@ -24,6 +24,21 @@ The features are:
- collates utf-8 text payloads into a 250-byte chunk buffer in the json parser - collates utf-8 text payloads into a 250-byte chunk buffer in the json parser
context object for ease of access context object for ease of access
## LEJP Context initialization
lejp doesn't allocate at all, you define a `struct lejp_ctx` usually on the
stack somewhere, and call `lejp_construct()` to initialize it.
To minimize surprises as lejp evolves, there is now a `flags` member of the
ctx, which defaults to zero for compatibility with older versions. After
the `lejp_construct()` call, you can set `ctx.flags` to indicate you want
newer options
|lejp flags|Meaning|
|---|---|
|LEJP_FLAG_FEAT_OBJECT_INDEXES|Provide indexes for { x, y, x } lists same as for arrays|
|LEJP_FLAG_LATEST|Alias indicating you want the "best" current options, even if incompatible with old behaviours|
## Type handling ## Type handling
LEJP leaves all numbers in text form, they are signalled in different callbacks LEJP leaves all numbers in text form, they are signalled in different callbacks
@ -87,6 +102,20 @@ or the match index from your path array starting from 1 for the first entry.
## Details of object and array indexes
LEJP maintains a "stack" of index counters, each element represents one level
in the current hierarchy that may have a list or array of objects in it.
The amount of levels currently is held in `ctx->ipos`, and `ctx->i[]` holds
`uint16_t` index counts for each level.
By querying these, you can understand at which element index in a hierarchy of
arrays in the JSON you are at, unambiguously.
By default that is done for each `[]` array level, if you set `ctx.flags` with
`LEJP_FLAG_FEAT_OBJECT_INDEXES` option, it is also done for each `{}` object
level, which can also take comma-separated lists that need index tracking.
## Comparison with LECP (CBOR parser) ## Comparison with LECP (CBOR parser)
LECP is based on the same principles as LEJP and shares most of the callbacks. LECP is based on the same principles as LEJP and shares most of the callbacks.

View file

@ -245,6 +245,10 @@ struct lejp_ctx {
/* short */ /* short */
uint16_t uni; uint16_t uni;
#define LEJP_FLAG_FEAT_OBJECT_INDEXES (1 << 0)
#define LEJP_FLAG_LATEST \
(LEJP_FLAG_FEAT_OBJECT_INDEXES)
uint16_t flags;
/* char */ /* char */

View file

@ -82,6 +82,7 @@ lejp_construct(struct lejp_ctx *ctx,
ctx->path[0] = '\0'; ctx->path[0] = '\0';
ctx->user = user; ctx->user = user;
ctx->line = 1; ctx->line = 1;
ctx->flags = 0; /* user may set after construction */
ctx->pst_sp = 0; ctx->pst_sp = 0;
ctx->pst[0].callback = callback; ctx->pst[0].callback = callback;
@ -287,6 +288,17 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
ret = LEJP_REJECT_IDLE_NO_BRACE; ret = LEJP_REJECT_IDLE_NO_BRACE;
goto reject; goto reject;
} }
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES) {
/* since insides of {} can have ',', we should
* add an index level so we can count them
*/
ctx->i[ctx->ipos++] = 0;
if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
ret = LEJP_REJECT_MP_DELIM_ISTACK;
goto reject;
}
}
if (ctx->pst[ctx->pst_sp].callback(ctx, if (ctx->pst[ctx->pst_sp].callback(ctx,
LEJPCB_OBJECT_START)) LEJPCB_OBJECT_START))
goto reject_callback; goto reject_callback;
@ -458,6 +470,16 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
c = LEJP_MEMBERS; c = LEJP_MEMBERS;
lejp_check_path_match(ctx); lejp_check_path_match(ctx);
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES) {
/* since insides of {} can have ',', we should
* add an index level so we can count them
*/
ctx->i[ctx->ipos++] = 0;
if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
ret = LEJP_REJECT_MP_DELIM_ISTACK;
goto reject;
}
}
if (ctx->pst[ctx->pst_sp].callback(ctx, if (ctx->pst[ctx->pst_sp].callback(ctx,
LEJPCB_OBJECT_START)) LEJPCB_OBJECT_START))
goto reject_callback; goto reject_callback;
@ -499,7 +521,9 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
ctx->pst[ctx->pst_sp].ppos = (unsigned char) ctx->pst[ctx->pst_sp].ppos = (unsigned char)
ctx->st[ctx->sp - 1].p; ctx->st[ctx->sp - 1].p;
ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i; ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
} } else
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES)
ctx->ipos--;
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0'; ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
if (ctx->path_match && if (ctx->path_match &&
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len) ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
@ -643,6 +667,11 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
if (c == ',') { if (c == ',') {
/* increment this stack level's index */ /* increment this stack level's index */
ctx->st[ctx->sp].s = LEJP_M_P; ctx->st[ctx->sp].s = LEJP_M_P;
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES)
if (ctx->ipos)
ctx->i[ctx->ipos - 1]++;
if (!ctx->sp) { if (!ctx->sp) {
ctx->pst[ctx->pst_sp].ppos = 0; ctx->pst[ctx->pst_sp].ppos = 0;
/* /*
@ -662,11 +691,15 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
*/ */
ctx->path_match = 0; ctx->path_match = 0;
lejp_check_path_match(ctx);
if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END) if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
break; break;
/* top level is definitely an array... */ /* top level is definitely an array... */
if (ctx->ipos) if (!(ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES))
ctx->i[ctx->ipos - 1]++; if (ctx->ipos)
ctx->i[ctx->ipos - 1]++;
ctx->st[ctx->sp].s = LEJP_MP_VALUE; ctx->st[ctx->sp].s = LEJP_MP_VALUE;
break; break;
} }
@ -687,7 +720,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
ctx->pst[ctx->pst_sp].ppos = (unsigned char) ctx->pst[ctx->pst_sp].ppos = (unsigned char)
ctx->st[ctx->sp - 1].p; ctx->st[ctx->sp - 1].p;
ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i; ctx->ipos = (unsigned char)ctx->st[ctx->sp - 1].i;
} } else
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES)
ctx->ipos--;
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0'; ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
if (ctx->path_match && if (ctx->path_match &&
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len) ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
@ -731,8 +767,11 @@ pop_level:
if (ctx->sp) { if (ctx->sp) {
ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp].p; ctx->pst[ctx->pst_sp].ppos = (unsigned char)ctx->st[ctx->sp].p;
ctx->ipos = (unsigned char)ctx->st[ctx->sp].i; ctx->ipos = (unsigned char)ctx->st[ctx->sp].i;
} } else
if (ctx->flags & LEJP_FLAG_FEAT_OBJECT_INDEXES)
ctx->ipos--;
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0'; ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
if (ctx->path_match && if (ctx->path_match &&
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len) ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
/* /*
@ -761,13 +800,14 @@ array_end:
ctx->pst[ctx->pst_sp].ppos = (unsigned char) ctx->pst[ctx->pst_sp].ppos = (unsigned char)
ctx->st[ctx->sp - 1].p; ctx->st[ctx->sp - 1].p;
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0'; ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
lejp_check_path_match(ctx);
break; break;
} }
if (c != ']') { if (c != ']') {
ret = LEJP_REJECT_MP_ARRAY_END_MISSING; ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
goto reject; goto reject;
} }
lejp_check_path_match(ctx);
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END; ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_END); ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_END);
if (defer) { if (defer) {

View file

@ -132,6 +132,11 @@ static const char * const json_tests[] = {
"{" /* test 11: array of arrays */ "{" /* test 11: array of arrays */
"\"array1\": [[\"a\", \"b\", \"b1\"], [\"c\", \"d\", \"d1\"]]," "\"array1\": [[\"a\", \"b\", \"b1\"], [\"c\", \"d\", \"d1\"]],"
"\"array2\": [[\"e\", \"f\", \"f1\"], [\"g\", \"h\", \"h1\"]]" "\"array2\": [[\"e\", \"f\", \"f1\"], [\"g\", \"h\", \"h1\"]]"
"}",
"{" /* test 12: test 11 but done with LEJP_FLAG_FEAT_OBJECT_INDEXES */
"\"array1\": [[\"a\", \"b\", \"b1\"], [\"c\", \"d\", \"d1\"]],"
"\"array2\": [[\"e\", \"f\", \"f1\"], [\"g\", \"h\", \"h1\"]]"
"}" "}"
}; };
@ -350,69 +355,118 @@ struct lejp_results {
{ 2, 0, 0, { 0 }, "", "123" }, { 2, 0, 0, { 0 }, "", "123" },
{ 16, 0, 0, { 0 }, "", "123" }, { 16, 0, 0, { 0 }, "", "123" },
{ 5, 0, 0, { 0 }, "array1", "123" }, { 5, 0, 0, { 0 }, "array1", "123" },
{ 14, 0, 0, { 0 }, "array1[]", "123" }, { 14, 0, 2, { 0 }, "array1[]", "123" },
{ 14, 1, 0, { 0, }, "array1[][]", "123" }, { 14, 1, 1, { 0, }, "array1[][]", "123" },
{ 11, 2, 0, { 0, 0, }, "array1[][]", "" }, { 11, 2, 1, { 0, 0, }, "array1[][]", "" },
{ 77, 2, 0, { 0, 0, }, "array1[][]", "a" }, { 77, 2, 1, { 0, 0, }, "array1[][]", "a" },
{ 11, 2, 0, { 0, 1, }, "array1[][]", "" }, { 11, 2, 1, { 0, 1, }, "array1[][]", "" },
{ 77, 2, 0, { 0, 1, }, "array1[][]", "b" }, { 77, 2, 1, { 0, 1, }, "array1[][]", "b" },
{ 11, 2, 0, { 0, 2, }, "array1[][]", "" }, { 11, 2, 1, { 0, 2, }, "array1[][]", "" },
{ 77, 2, 0, { 0, 2, }, "array1[][]", "b1" }, { 77, 2, 1, { 0, 2, }, "array1[][]", "b1" },
{ 15, 1, 0, { 0, }, "array1[]", "b1" }, { 15, 1, 2, { 0, }, "array1[]", "b1" },
{ 14, 1, 0, { 1, }, "array1[][]", "b1" }, { 14, 1, 1, { 1, }, "array1[][]", "b1" },
{ 11, 2, 0, { 1, 0, }, "array1[][]", "" }, { 11, 2, 1, { 1, 0, }, "array1[][]", "" },
{ 77, 2, 0, { 1, 0, }, "array1[][]", "c" }, { 77, 2, 1, { 1, 0, }, "array1[][]", "c" },
{ 11, 2, 0, { 1, 1, }, "array1[][]", "" }, { 11, 2, 1, { 1, 1, }, "array1[][]", "" },
{ 77, 2, 0, { 1, 1, }, "array1[][]", "d" }, { 77, 2, 1, { 1, 1, }, "array1[][]", "d" },
{ 11, 2, 0, { 1, 2, }, "array1[][]", "" }, { 11, 2, 1, { 1, 2, }, "array1[][]", "" },
{ 77, 2, 0, { 1, 2, }, "array1[][]", "d1" }, { 77, 2, 1, { 1, 2, }, "array1[][]", "d1" },
{ 15, 1, 0, { 1, }, "array1[]", "d1" }, { 15, 1, 2, { 1, }, "array1[]", "d1" },
{ 15, 1, 0, { 1, }, "array1[]", "d1" }, { 15, 1, 2, { 1, }, "array1[]", "d1" },
{ 5, 1, 0, { 1, }, "array2", "d1" }, { 5, 1, 0, { 1, }, "array2", "d1" },
{ 14, 1, 0, { 1, }, "array2[]", "d1" }, { 14, 1, 2, { 1, }, "array2[]", "d1" },
{ 14, 2, 0, { 1, 0, }, "array2[][]", "d1" }, { 14, 2, 1, { 1, 0, }, "array2[][]", "d1" },
{ 11, 3, 0, { 1, 0, 0, }, "array2[][]", "" }, { 11, 3, 1, { 1, 0, 0, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 0, 0, }, "array2[][]", "e" }, { 77, 3, 1, { 1, 0, 0, }, "array2[][]", "e" },
{ 11, 3, 0, { 1, 0, 1, }, "array2[][]", "" }, { 11, 3, 1, { 1, 0, 1, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 0, 1, }, "array2[][]", "f" }, { 77, 3, 1, { 1, 0, 1, }, "array2[][]", "f" },
{ 11, 3, 0, { 1, 0, 2, }, "array2[][]", "" }, { 11, 3, 1, { 1, 0, 2, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 0, 2, }, "array2[][]", "f1" }, { 77, 3, 1, { 1, 0, 2, }, "array2[][]", "f1" },
{ 15, 2, 0, { 1, 0, }, "array2[]", "f1" }, { 15, 2, 2, { 1, 0, }, "array2[]", "f1" },
{ 14, 2, 0, { 1, 1, }, "array2[][]", "f1" }, { 14, 2, 1, { 1, 1, }, "array2[][]", "f1" },
{ 11, 3, 0, { 1, 1, 0, }, "array2[][]", "" }, { 11, 3, 1, { 1, 1, 0, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 1, 0, }, "array2[][]", "g" }, { 77, 3, 1, { 1, 1, 0, }, "array2[][]", "g" },
{ 11, 3, 0, { 1, 1, 1, }, "array2[][]", "" }, { 11, 3, 1, { 1, 1, 1, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 1, 1, }, "array2[][]", "h" }, { 77, 3, 1, { 1, 1, 1, }, "array2[][]", "h" },
{ 11, 3, 0, { 1, 1, 2, }, "array2[][]", "" }, { 11, 3, 1, { 1, 1, 2, }, "array2[][]", "" },
{ 77, 3, 0, { 1, 1, 2, }, "array2[][]", "h1" }, { 77, 3, 1, { 1, 1, 2, }, "array2[][]", "h1" },
{ 15, 2, 0, { 1, 1, }, "array2[]", "h1" }, { 15, 2, 2, { 1, 1, }, "array2[]", "h1" },
{ 15, 2, 0, { 1, 1, }, "array2[]", "h1" }, { 15, 2, 2, { 1, 1, }, "array2[]", "h1" },
{ 17, 2, 0, { 1, 1, }, "array2[]", "h1" }, { 17, 2, 0, { 1, 1, }, "array2[]", "h1" },
{ 3, 2, 0, { 1, 1, }, "array2[]", "h1" }, { 3, 2, 0, { 1, 1, }, "array2[]", "h1" },
}, r12[] = { /* test 11 but done with LEJP_FLAG_FEAT_OBJECT_INDEXES */
{ 0, 0, 0, { 0 }, "", "h1" },
{ 2, 0, 0, { 0 }, "", "h1" },
{ 16, 1, 0, { 0, }, "", "h1" },
{ 5, 1, 0, { 0, }, "array1", "h1" },
{ 14, 1, 2, { 0, }, "array1[]", "h1" },
{ 14, 2, 1, { 0, 0, }, "array1[][]", "h1" },
{ 11, 3, 1, { 0, 0, 0, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 0, 0, }, "array1[][]", "a" },
{ 11, 3, 1, { 0, 0, 1, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 0, 1, }, "array1[][]", "b" },
{ 11, 3, 1, { 0, 0, 2, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 0, 2, }, "array1[][]", "b1" },
{ 15, 2, 2, { 0, 0, }, "array1[]", "b1" },
{ 14, 2, 1, { 0, 1, }, "array1[][]", "b1" },
{ 11, 3, 1, { 0, 1, 0, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 1, 0, }, "array1[][]", "c" },
{ 11, 3, 1, { 0, 1, 1, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 1, 1, }, "array1[][]", "d" },
{ 11, 3, 1, { 0, 1, 2, }, "array1[][]", "" },
{ 77, 3, 1, { 0, 1, 2, }, "array1[][]", "d1" },
{ 15, 2, 2, { 0, 1, }, "array1[]", "d1" },
{ 15, 1, 2, { 0, 1, }, "array1[]", "d1" },
{ 5, 1, 0, { 1, }, "array2", "d1" },
{ 14, 1, 2, { 1, }, "array2[]", "d1" },
{ 14, 2, 1, { 1, 0, }, "array2[][]", "d1" },
{ 11, 3, 1, { 1, 0, 0, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 0, 0, }, "array2[][]", "e" },
{ 11, 3, 1, { 1, 0, 1, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 0, 1, }, "array2[][]", "f" },
{ 11, 3, 1, { 1, 0, 2, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 0, 2, }, "array2[][]", "f1" },
{ 15, 2, 2, { 1, 0, }, "array2[]", "f1" },
{ 14, 2, 1, { 1, 1, }, "array2[][]", "f1" },
{ 11, 3, 1, { 1, 1, 0, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 1, 0, }, "array2[][]", "g" },
{ 11, 3, 1, { 1, 1, 1, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 1, 1, }, "array2[][]", "h" },
{ 11, 3, 1, { 1, 1, 2, }, "array2[][]", "" },
{ 77, 3, 1, { 1, 1, 2, }, "array2[][]", "h1" },
{ 15, 2, 2, { 1, 1, }, "array2[]", "h1" },
{ 15, 1, 2, { 1, }, "array2[]", "h1" },
{ 17, 1, 0, { 1, }, "array2[]", "h1" },
{ 3, 1, 0, { 1, }, "array2[]", "h1" },
}; };
static const char * const tok[] = {
"something",
}, * const tok_test11[] = { /* matches for test 11, 12 */
"*[][]",
"*[]",
};
struct lejp_results_pkg { struct lejp_results_pkg {
const struct lejp_results *r; const struct lejp_results *r;
size_t len; size_t len;
const char * const *tokens;
size_t tokens_len;
uint16_t ctx_flags;
} rpkg[] = { } rpkg[] = {
{ r1, LWS_ARRAY_SIZE(r1) }, { r1, LWS_ARRAY_SIZE(r1), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r2, LWS_ARRAY_SIZE(r2) }, { r2, LWS_ARRAY_SIZE(r2), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r3, LWS_ARRAY_SIZE(r3) }, { r3, LWS_ARRAY_SIZE(r3), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r4, LWS_ARRAY_SIZE(r4) }, { r4, LWS_ARRAY_SIZE(r4), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r5, LWS_ARRAY_SIZE(r5) }, { r5, LWS_ARRAY_SIZE(r5), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r6, LWS_ARRAY_SIZE(r6) }, { r6, LWS_ARRAY_SIZE(r6), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r7, LWS_ARRAY_SIZE(r7) }, { r7, LWS_ARRAY_SIZE(r7), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r8, LWS_ARRAY_SIZE(r8) }, { r8, LWS_ARRAY_SIZE(r8), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r9, LWS_ARRAY_SIZE(r9) }, { r9, LWS_ARRAY_SIZE(r9), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r10, LWS_ARRAY_SIZE(r10) }, { r10, LWS_ARRAY_SIZE(r10), tok, LWS_ARRAY_SIZE(tok), 0 },
{ r11, LWS_ARRAY_SIZE(r11) }, { r11, LWS_ARRAY_SIZE(r11), tok_test11, LWS_ARRAY_SIZE(tok_test11), 0 },
}; { r12, LWS_ARRAY_SIZE(r12), tok_test11, LWS_ARRAY_SIZE(tok_test11),
LEJP_FLAG_FEAT_OBJECT_INDEXES },
static const char * const tok[] = {
"something",
}; };
@ -491,7 +545,8 @@ int main(int argc, const char **argv)
lwsl_user("%s: ++++++++++++++++ test %d\n", __func__, m + 1); lwsl_user("%s: ++++++++++++++++ test %d\n", __func__, m + 1);
step = 0; step = 0;
lejp_construct(&ctx, test_cb, NULL, tok, LWS_ARRAY_SIZE(tok)); lejp_construct(&ctx, test_cb, NULL, rpkg[m].tokens, (uint8_t)rpkg[m].tokens_len);
ctx.flags = rpkg[m].ctx_flags;
lwsl_hexdump_info(json_tests[m], strlen(json_tests[m])); lwsl_hexdump_info(json_tests[m], strlen(json_tests[m]));