#ifndef CSONPATH_DO_GET_NOTFOUND
#define CSONPATH_DO_GET_NOTFOUND(this_idx) \
do { \
walker += 1; \
while (*walker != CSONPATH_INST_END) { \
if (*walker == CSONPATH_INST_OR) { \
goto next_inst; \
} \
walker = csonpath_walker_next_inst(walker); \
} \
return CSONPATH_NONE_FOUND_RET; \
} while (0)
#endif
#ifndef CSONPATH_PRE_GET
#define CSONPATH_PRE_GET(this_idx)
#endif
#ifndef CSONPATH_PRE_GET_OBJ
#define CSONPATH_PRE_GET_OBJ(x) CSONPATH_PRE_GET(x)
#endif
#ifndef CSONPATH_PRE_GET_ROOT
#define CSONPATH_PRE_GET_ROOT
#endif
#ifndef CSONPATH_DO_DECLARATION
#define CSONPATH_DO_DECLARATION
#endif
#ifndef CSONPATH_DO_POST_FIND_OBJ
#define CSONPATH_DO_POST_FIND_OBJ
#endif
#ifndef CSONPATH_DO_POST_FIND_ARRAY
#define CSONPATH_DO_POST_FIND_ARRAY
#endif
#ifndef CSONPATH_DO_EXTRA_DECLARATION
#define CSONPATH_DO_EXTRA_DECLARATION
#endif
#ifndef CSONPATH_DO_FIND_ALL_CLEAUP
#define CSONPATH_DO_FIND_ALL_CLEAUP
#endif
#ifndef CSONPATH_DO_EXTRA_ARGS
#define CSONPATH_DO_EXTRA_ARGS
#endif
#ifndef CSONPATH_DO_EXTRA_ARGS_NEESTED
# ifdef CSONPATH_DO_EXTRA_ARGS_IN
# define CSONPATH_DO_EXTRA_ARGS_NEESTED CSONPATH_DO_EXTRA_ARGS_IN
# else
# define CSONPATH_DO_EXTRA_ARGS_NEESTED
# endif
#endif
#ifndef CSONPATH_DO_EXTRA_ARGS_FIND_ALL
#define CSONPATH_DO_EXTRA_ARGS_FIND_ALL CSONPATH_DO_EXTRA_ARGS_NEESTED
#endif
#ifndef CSONPATH_DO_EXTRA_ARGS_IN
#define CSONPATH_DO_EXTRA_ARGS_IN
#endif
#ifndef CSONPATH_DO_POST_OPERATION
#define CSONPATH_DO_POST_OPERATION
#endif
#ifndef CSONPATH_DO_PRE_OPERATION
#define CSONPATH_DO_PRE_OPERATION
#endif
#ifndef CSONPATH_DO_FIND_ALL_PRE_LOOP
#define CSONPATH_DO_FIND_ALL_PRE_LOOP
#endif
#ifndef CSONPATH_DO_FOREACH_PRE_SET
#define CSONPATH_DO_FOREACH_PRE_SET
#endif
#ifndef CSONPATH_DO_GET_ALL_OUT
#define CSONPATH_DO_GET_ALL_OUT CSONPATH_DO_FIND_ALL_OUT
#endif
#ifndef CSONPATH_DO_FILTER_OUT
#define CSONPATH_DO_FILTER_OUT CSONPATH_DO_FIND_ALL_OUT
#endif
#ifndef CSONPATH_DO_FILTER_PRE_LOOP
#define CSONPATH_DO_FILTER_PRE_LOOP
#endif
#ifndef CSONPATH_DO_FILTER_LOOP_PRE_SET
#define CSONPATH_DO_FILTER_LOOP_PRE_SET
#endif
#ifndef CSONPATH_DO_RANGE
#define CSONPATH_DO_RANGE CSONPATH_DO_FIND_ALL
#endif
#ifndef CSONPATH_DO_GET_UNION_POST
#define CSONPATH_DO_GET_UNION_POST CSONPATH_DO_FIND_ALL
#endif
#ifndef CSONPATH_DO_RANGE_PRE_LOOP
#define CSONPATH_DO_RANGE_PRE_LOOP CSONPATH_DO_FIND_ALL_PRE_LOOP
#endif
#ifndef CAT
# define CATCAT_(a, b, c) a ## b ## c
# define CATCAT(a, b, c) CATCAT_(a, b, c)
# define CAT_(a, b) a ## b
# define CAT(a, b) CAT_(a, b)
#endif
#define csonpath_do_internal__(name) CATCAT(CSONPATH_FUNC(csonpath_), name, _internal)
#define csonpath_do_internal csonpath_do_internal__(CSONPATH_DO_FUNC_NAME)
static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const static 1],
CSONPATH_JSON origin,
CSONPATH_JSON value,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLARATION);
#define csonpath_do_dotdot__(name) CATCAT(CSONPATH_FUNC(csonpath_), name, _dotdot)
#define csonpath_do_dotdot csonpath_do_dotdot__(CSONPATH_DO_FUNC_NAME)
static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(const struct csonpath cjp[const static 1],
CSONPATH_JSON origin,
CSONPATH_JSON tmp,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLARATION)
{
CSONPATH_JSON el;
CSONPATH_DO_DECLARATION;
const int is_obj = CSONPATH_IS_OBJ(tmp);
intptr_t key_idx;
CSONPATH_DO_RET_TYPE tret = CSONPATH_NONE_FOUND_RET;
const char *next_inst = NULL;
(void)ctx;
CSONPATH_DO_FIND_ALL_PRE_LOOP;
const int is_wildcard = (unsigned char)walker[1] == CSONPATH_INST_GET_ALL;
if (is_obj) {
const char *key;
CSONPATH_FOREACH_OBJ(tmp, el, key) {
key_idx = (intptr_t)key;
(void)key_idx;
CSONPATH_DO_FOREACH_PRE_SET;
if (is_wildcard || !strcmp(key, walker + 1)) {
if (!next_inst)
next_inst = csonpath_walker_next_inst(walker);
tret = csonpath_do_internal(cjp, origin, el, tmp,
next_inst
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FIND_ALL;
}
if (CSONPATH_IS_OBJ(el) || CSONPATH_IS_ARRAY(el)) {
tret = csonpath_do_dotdot(cjp, origin, el, tmp, walker
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FIND_ALL;
}
}
} else if (CSONPATH_IS_ARRAY(tmp)) {
CSONPATH_FOREACH_ARRAY(tmp, el, key_idx) {
(void)key_idx;
CSONPATH_DO_FOREACH_PRE_SET;
if (is_wildcard) {
if (!next_inst)
next_inst = csonpath_walker_next_inst(walker);
tret = csonpath_do_internal(cjp, origin, el, tmp,
next_inst
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FIND_ALL;
}
if (CSONPATH_IS_OBJ(el) || CSONPATH_IS_ARRAY(el)) {
tret = csonpath_do_dotdot(cjp, origin, el, tmp, walker
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FIND_ALL;
}
}
}
CSONPATH_DO_FIND_ALL_OUT;
return tret;
}
static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const static 1],
CSONPATH_JSON origin,
CSONPATH_JSON value,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLARATION)
{
CSONPATH_JSON tmp = value;
CSONPATH_DO_DECLARATION;
(void)ctx;
while (!csonpath_is_endish_inst(*walker)) {
switch (*walker) {
case CSONPATH_INST_UNION_JMP:
{
walker = csonpath_skipp_union_jmp(walker);
}
case CSONPATH_INST_UNION_END:
break;
case CSONPATH_INST_ROOT:
{
CSONPATH_PRE_GET_ROOT
value = origin;
tmp = value;
ctx = CSONPATH_NULL;
}
break;
case CSONPATH_SWITCH_ROOT:
{
int root_idx = (unsigned char)walker[1];
if (cjp->extra_roots == CSONPATH_NULL ||
(size_t)root_idx >= (size_t)CSONPATH_ARRAY_LENGTH((CSONPATH_JSON)cjp->extra_roots)) {
CSONPATH_GETTER_ERR("extra root index %d out of bounds\n",
root_idx);
}
value = CSONPATH_AT((CSONPATH_JSON)cjp->extra_roots, root_idx);
tmp = value;
ctx = CSONPATH_NULL;
++walker;
}
break;
case CSONPATH_INST_FILTER_KEY_EXIST:
case CSONPATH_INST_FILTER_KEY_EQ:
case CSONPATH_INST_FILTER_KEY_REG_EQ:
case CSONPATH_INST_FILTER_KEY_NOT_EQ:
case CSONPATH_INST_FILTER_KEY_SUPERIOR:
case CSONPATH_INST_FILTER_KEY_INFERIOR:
case CSONPATH_INST_FILTER_KEY_SUPERIOR_EQ:
case CSONPATH_INST_FILTER_KEY_INFERIOR_EQ:
{
CSONPATH_JSON el;
int operation_in = *walker, operation = *walker;
const char *owalker;
int filter_next_in = (unsigned char)*(walker+1), filter_next = (unsigned char)*(walker+1);
const char *next = walker + 2;
int foreach_idx;
(void) foreach_idx;
CSONPATH_DO_FILTER_PRE_LOOP;
if (!CSONPATH_IS_ARRAY(tmp)) {
CSONPATH_DO_FILTER_OUT;
break;
}
CSONPATH_FOREACH_ARRAY(tmp, el, foreach_idx)
{
intptr_t key_idx = foreach_idx;
filter_next = filter_next_in;
operation = operation_in;
(void)key_idx;
owalker = next;
match_and_or_or:
if (CSONPATH_IS_OBJ(el)) {
CSONPATH_JSON el2 = el;
CSONPATH_DO_FILTER_LOOP_PRE_SET;
el2 = CSONPATH_FUNC(csonpath_crawl_filter_el)(cjp, &owalker, el2, filter_next);
if (CSONPATH_FUNC(csonpath_make_match)(cjp, origin, el2, &owalker, operation)) {
if (*owalker == CSONPATH_INST_FILTER_AND) {
++owalker;
operation = *owalker;
++owalker;
filter_next = *owalker;
++owalker;
goto match_and_or_or;
}
CSONPATH_DO_RET_TYPE tret =
csonpath_do_internal(cjp, origin, el, tmp, owalker
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FILTER_FIND;
}
}
}
CSONPATH_DO_FILTER_OUT;
break;
}
case CSONPATH_INST_FIND_ALL:
{
if (CSONPATH_IS_OBJ(tmp) || CSONPATH_IS_ARRAY(tmp)) {
CSONPATH_DO_RET_TYPE tret =
csonpath_do_dotdot(cjp, origin, tmp, ctx,
walker CSONPATH_DO_EXTRA_ARGS_FIND_ALL);
CSONPATH_DO_FIND_ALL_CLEAUP;
return tret;
} else {
return CSONPATH_NONE_FOUND_RET;
}
}
case CSONPATH_INST_RANGE:
{
if (!CSONPATH_IS_ARRAY(tmp)) {
return CSONPATH_NONE_FOUND_RET;
}
CSONPATH_JSON el;
intptr_t key_idx;
int getter_instruction;
(void)key_idx;
++walker;
getter_instruction = walker[0];
++walker;
unsigned int beg = csonpath_int_from_walker(getter_instruction, &walker);
getter_instruction = walker[0];
++walker;
unsigned int end = csonpath_int_from_walker(getter_instruction, &walker);
if (!end)
end = -1;
CSONPATH_DO_RANGE_PRE_LOOP;
CSONPATH_FOREACH_ARRAY(tmp, el, key_idx) {
if (key_idx < beg) {
key_idx = beg - 1;
continue;
}
if (key_idx >= end)
break;
CSONPATH_DO_FOREACH_PRE_SET
CSONPATH_DO_RET_TYPE tret =
csonpath_do_internal(cjp, origin, el, tmp, walker
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_RANGE;
}
CSONPATH_DO_GET_ALL_OUT;
break;
}
case CSONPATH_INST_GET_UNION:
{
intptr_t key_idx = 0;
int need_reloop_in = 0;
(void)need_reloop_in;
(void)key_idx;
do {
++walker;
int union_cnt = 0;
CSONPATH_DO_RET_TYPE tret = csonpath_do_internal(cjp, origin, tmp, CSONPATH_NULL,
walker
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_GET_UNION_POST;
while (1) {
walker = csonpath_walker_next_inst(walker);
if (*walker == CSONPATH_INST_GET_UNION)
++union_cnt;
if (*walker == CSONPATH_INST_UNION_JMP && !union_cnt)
break;
if (*walker == CSONPATH_INST_UNION_END) {
if (union_cnt)
--union_cnt;
else
break;
}
}
} while (*walker != CSONPATH_INST_UNION_END);
CSONPATH_DO_GET_ALL_OUT;
break;
}
case CSONPATH_INST_GET_ALL:
{
CSONPATH_JSON el;
CSONPATH_DO_FIND_ALL_PRE_LOOP;
CSONPATH_FOREACH(tmp, el, {
CSONPATH_DO_FOREACH_PRE_SET
CSONPATH_DO_RET_TYPE tret =
csonpath_do_internal(cjp, origin, el, tmp,
walker + 1
CSONPATH_DO_EXTRA_ARGS_NEESTED);
CSONPATH_DO_FIND_ALL;
});
CSONPATH_DO_GET_ALL_OUT;
break;
}
case CSONPATH_INST_GET_SUBPATH:
{
const char *end_sentinel = walker;
const char *owalker = walker;
owalker = csonpath_walker_next_inst(owalker);
CSONPATH_JSON jret = CSONPATH_FUNC(csonpath_find_first_internal)(
cjp, origin, origin, CSONPATH_NULL, owalker, &end_sentinel);
owalker = end_sentinel;
if (tmp != CSONPATH_NULL)
ctx = tmp;
if (CSONPATH_IS_NUM(jret)) {
int this_idx = CSONPATH_GET_NUM(jret);
CSONPATH_PRE_GET(this_idx);
tmp = CSONPATH_AT(tmp, this_idx);
if (tmp == CSONPATH_NULL) {
walker = owalker;
CSONPATH_DO_GET_NOTFOUND(this_idx);
}
CSONPATH_DO_POST_FIND_ARRAY;
} else if (CSONPATH_IS_STR(jret)) {
CSONPATH_CLEANUP_STR const char *this_idx = CSONPATH_GET_STR(jret);
CSONPATH_PRE_GET_OBJ(this_idx);
tmp = CSONPATH_GET(tmp, this_idx);
if (tmp == CSONPATH_NULL) {
walker = owalker;
CSONPATH_DO_GET_NOTFOUND(this_idx);
}
CSONPATH_DO_POST_FIND_OBJ;
} else {
CSONPATH_GETTER_ERR("GET_SUBPATH return need to be either number or str");
}
walker = owalker;
break;
}
case CSONPATH_INST_TYPECHECK:
{
int type = (unsigned char)walker[1];
++walker;
switch (type) {
case CSONPATH_STR:
if (!CSONPATH_IS_STR(tmp))
return CSONPATH_NONE_FOUND_RET;
break;
case CSONPATH_INTEGER:
if (!CSONPATH_IS_NUM(tmp))
return CSONPATH_NONE_FOUND_RET;
break;
case CSONPATH_NONE:
if (!CSONPATH_IS_NULL(tmp))
return CSONPATH_NONE_FOUND_RET;
break;
default:
CSONPATH_GETTER_ERR("unknown typecheck %d, is csonpath corrupted ?\n", type);
break;
}
break;
}
case CSONPATH_INST_GET_OBJ:
{
CSONPATH_UNUSED const char *this_idx = &walker[1];
if (tmp != CSONPATH_NULL)
ctx = tmp;
CSONPATH_PRE_GET_OBJ(this_idx);
++walker;
tmp = CSONPATH_GET(tmp, walker);
walker += strlen(walker);
if (tmp == CSONPATH_NULL) {
CSONPATH_DO_GET_NOTFOUND(this_idx);
}
CSONPATH_DO_POST_FIND_OBJ;
break;
}
case CSONPATH_INST_GET_ARRAY_SMALL:
{
int this_idx;
if (tmp != CSONPATH_NULL)
ctx = tmp;
this_idx = (int)walker[1];
CSONPATH_PRE_GET(this_idx);
tmp = CSONPATH_AT(tmp, this_idx);
walker += 1;
if (tmp == CSONPATH_NULL) {
CSONPATH_DO_GET_NOTFOUND(this_idx);
}
CSONPATH_DO_POST_FIND_ARRAY;
break;
}
case CSONPATH_INST_GET_ARRAY_BIG:
if (tmp != CSONPATH_NULL)
ctx = tmp;
{
CSONPATH_UNUSED int this_idx;
union {int n; char c[4];} to_num =
{ .c= { walker[1], walker[2], walker[3], walker[4] } };
this_idx = to_num.n;
CSONPATH_PRE_GET(this_idx);
tmp = CSONPATH_AT(tmp, to_num.n);
walker += 4;
if (tmp == CSONPATH_NULL) {
CSONPATH_DO_GET_NOTFOUND(this_idx);
}
CSONPATH_DO_POST_FIND_ARRAY;
break;
}
default:
CSONPATH_GETTER_ERR("unimplemented %d (%s) at idx %d\n", *walker,
*walker <= CSONPATH_INST_BROKEN ?
csonpath_instuction_str[(int)*walker] : "(unknow)",
(int)(intptr_t)(walker - cjp->data));
}
next_inst:
++walker;
}
CSONPATH_DO_RETURN;
}
#define csonpath_do__(name) CAT(CSONPATH_FUNC(csonpath_), name)
#define csonpath_do_ csonpath_do__(CSONPATH_DO_FUNC_NAME)
CSONPATH_STATINLINE CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
CSONPATH_JSON value CSONPATH_DO_EXTRA_ARGS)
{
char *walker = cjp->data;
CSONPATH_JSON ctx = CSONPATH_NULL;
(void)ctx;
if (*walker == CSONPATH_INST_BROKEN) {
CSONPATH_GETTER_ERR("fail to compile: %s\n", cjp->compile_error ?
cjp->compile_error : "(unknow error)");
}
CSONPATH_DO_PRE_OPERATION;
CSONPATH_DO_RET_TYPE ret = csonpath_do_internal(cjp, value, value,
CSONPATH_NULL,
walker CSONPATH_DO_EXTRA_ARGS_IN);
CSONPATH_DO_POST_OPERATION;
return ret;
}
#ifndef CSONPATH_NO_UNDEF
#undef CSONPATH_PRE_GET_ROOT
#undef CSONPATH_PRE_GET
#undef CSONPATH_DO_PRE_OPERATION
#undef CSONPATH_DO_POST_OPERATION
#undef CSONPATH_DO_FUNC_NAME
#undef CSONPATH_DO_RET_TYPE
#undef CSONPATH_DO_RETURN
#undef CSONPATH_DO_DECLARATION
#undef CSONPATH_DO_FIND_ALL
#undef CSONPATH_DO_FIND_ALL_OUT
#undef CSONPATH_DO_POST_FIND_ARRAY
#undef CSONPATH_DO_POST_FIND_OBJ
#undef CSONPATH_DO_EXTRA_ARGS_NEESTED
#undef CSONPATH_DO_EXTRA_ARGS_IN
#undef CSONPATH_DO_EXTRA_ARGS_FIND_ALL
#undef CSONPATH_DO_EXTRA_ARGS
#undef CSONPATH_DO_EXTRA_DECLARATION
#undef CSONPATH_DO_FIND_ALL_PRE_LOOP
#undef CSONPATH_DO_FOREACH_PRE_SET
#undef CSONPATH_DO_GET_ALL_OUT
#undef CSONPATH_DO_GET_NOTFOUND
#undef CSONPATH_DO_FIND_ALL_CLEAUP
#undef CSONPATH_DO_FILTER_OUT
#undef CSONPATH_DO_FILTER_PRE_LOOP
#undef CSONPATH_DO_FILTER_FIND
#undef CSONPATH_DO_FILTER_LOOP_PRE_SET
#undef CSONPATH_DO_RANGE
#undef CSONPATH_DO_RANGE_PRE_LOOP
#undef CSONPATH_PRE_GET_OBJ
#undef CSONPATH_DO_GET_UNION_POST
#endif