Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ YYJSON_LDFLAGS=$(shell pkg-config --libs yyjson)

include config.mk

all: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union
all: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-json-audit-bugs

YYJSON_TESTS=test-yyjson

Expand Down Expand Up @@ -43,10 +43,13 @@ test-json-get-array-big-index: tests/json-c/get-array-big-index.c csonpath_json-
test-json-union: tests/json-c/union.c csonpath_json-c.h csonpath.h csonpath_do.h
$(CC) tests/json-c/union.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-union $(JSON_C_LDFLAGS) $(LDFLAGS)

test-json-audit-bugs: tests/json-c/audit-bugs.c csonpath_json-c.h csonpath.h csonpath_do.h
$(CC) tests/json-c/audit-bugs.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-audit-bugs $(JSON_C_LDFLAGS) $(LDFLAGS)

test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do.h
$(CC) tests/yyjson/test-yyjson.c $(EXTRA_FILES) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-yyjson $(YYJSON_LDFLAGS) $(LDFLAGS)

tests-c: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-yyjson
tests-c: test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-json-audit-bugs test-yyjson
./test-json-c-get-a
./test-json-update
./test-json-filter
Expand All @@ -55,6 +58,7 @@ test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do
./test-json-filter-and-missing-key
./test-json-get-array-big-index
./test-json-union
./test-json-audit-bugs
./test-yyjson

pip-dev:
Expand All @@ -66,5 +70,5 @@ tests-py: pip-dev
tests: tests-py tests-c

clean:
rm -rvf test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-yyjson
rm -rvf test-json-c-get-a test-json-update test-json-filter test-json-subpath test-json-c-array-root test-json-filter-and-missing-key test-json-get-array-big-index test-json-union test-json-audit-bugs test-yyjson

74 changes: 43 additions & 31 deletions csonpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ struct csonpath_child_info {
#define CSONPATH_ERROR_MAX_SIZE 1024
#define CSONPATH_TMP_BUF_SIZE 256

#define CSONPATH_FILTER_PUSH(dst, cnt, c, walk_ptr) do { \
if ((cnt + 1) >= CSONPATH_TMP_BUF_SIZE) { \
CSONPATH_COMPILE_ERR(tmp, walk_ptr - orig, "%s", "filter key too long"); \
goto error; \
} \
(dst)[(cnt)++] = (c); \
} while (0)

/* I'm assuming error message won't be longer than 125 */
#define CSONPATH_COMPILE_ERR(tmp, idx, args...) do { \
int ltmp = strlen(tmp), lidx, oidx = idx; \
Expand Down Expand Up @@ -455,7 +463,6 @@ static void push_filter_getter(struct csonpath *cjp, int *inst_idx, int nb_gette
csonpath_push_char(cjp, filter_getter[i], inst_idx);
}
*filter_end = (nb_getter_inst - 1);

}

static int csonpath_compile_do(struct csonpath *cjp, const char orig[static 1],
Expand Down Expand Up @@ -547,7 +554,7 @@ static int csonpath_compile_do(struct csonpath *cjp, const char orig[static 1],
}
filter_again_root:
inst = CSONPATH_INST_GET_OBJ;
filter_getter[nb_getter_inst++] = CSONPATH_INST_GET_OBJ;
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, CSONPATH_INST_GET_OBJ, walker);
++walker;

/* skipp blank */
Expand Down Expand Up @@ -585,12 +592,12 @@ static int csonpath_compile_do(struct csonpath *cjp, const char orig[static 1],
}
++walker;
for (next = walker; *next != getter_end; ++next)
filter_getter[nb_getter_inst++] = *next;
filter_getter[nb_getter_inst++] = 0;
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, *next, next);
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, 0, next);
} else {
for (next = walker; csonpath_is_dot_operand(*next); ++next)
filter_getter[nb_getter_inst++] = *next;
filter_getter[nb_getter_inst++] = 0;
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, *next, next);
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, 0, next);
}
if (!*next) {
CSONPATH_COMPILE_ERR(tmp, next - orig,
Expand All @@ -606,11 +613,11 @@ static int csonpath_compile_do(struct csonpath *cjp, const char orig[static 1],
}
if (to_check == '.') {
walker = next + 1;
filter_getter[nb_getter_inst++] = CSONPATH_INST_GET_OBJ;
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, CSONPATH_INST_GET_OBJ, walker);
goto filter_again;
} else if (to_check == '[') {
walker = next + 1;
filter_getter[nb_getter_inst++] = CSONPATH_INST_GET_OBJ;
CSONPATH_FILTER_PUSH(filter_getter, nb_getter_inst, CSONPATH_INST_GET_OBJ, walker);
getter_end = *walker;
goto filter_again;
}
Expand Down Expand Up @@ -1103,7 +1110,7 @@ need_reloop_in = 0;

#define CSONPATH_DO_FIND_ALL_OUT if (end_sentinel) *end_sentinel = walker; return CSONPATH_NULL

#define CSONPATH_DO_EXTRA_DECLATION , const char **end_sentinel
#define CSONPATH_DO_EXTRA_DECLARATION , const char **end_sentinel
#define CSONPATH_DO_EXTRA_ARGS_IN , NULL
#define CSONPATH_DO_EXTRA_ARGS_NEESTED , end_sentinel

Expand Down Expand Up @@ -1136,7 +1143,7 @@ need_reloop_in = 0;
return ret_ar;

#define CSONPATH_DO_EXTRA_ARGS_IN , ret_ar
#define CSONPATH_DO_EXTRA_DECLATION , CSONPATH_FIND_ALL_RET ret_ar
#define CSONPATH_DO_EXTRA_DECLARATION , CSONPATH_FIND_ALL_RET ret_ar

#include "csonpath_do.h"

Expand All @@ -1158,10 +1165,12 @@ need_reloop_in = 0;

#define CSONPATH_DO_RET_TYPE int
#define CSONPATH_DO_RETURN \
({if (ctx == in_ctx && need_reloop && \
CSONPATH_NEED_FOREACH_REDO(ctx)) \
*need_reloop = 1; \
CSONPATH_REMOVE_CHILD(ctx, child_info); return 1;})
({if (ctx == in_ctx && need_reloop && \
CSONPATH_NEED_FOREACH_REDO(ctx)) \
*need_reloop = 1; \
if (child_info.type == CSONPATH_NONE) \
return 0; \
CSONPATH_REMOVE_CHILD(ctx, child_info); return 1;})

#define CSONPATH_PRE_GET_OBJ(val) \
const char *to_del = val;
Expand Down Expand Up @@ -1200,7 +1209,7 @@ need_reloop_in = 0;
nb_res += tret; \
})

#define CSONPATH_DO_EXTRA_DECLATION , struct csonpath_child_info child_info, int *need_reloop
#define CSONPATH_DO_EXTRA_DECLARATION , struct csonpath_child_info child_info, int *need_reloop

#define CSONPATH_DO_EXTRA_ARGS_IN , (struct csonpath_child_info) {.type = CSONPATH_NONE}, NULL

Expand Down Expand Up @@ -1273,7 +1282,7 @@ need_reloop_in = 0;
csonpath_child_info_set(&(struct csonpath_child_info ){}, tmp, (intptr_t)key_idx), &need_reloop_in
#define CSONPATH_DO_EXTRA_ARGS , CSONPATH_JSON to_update
#define CSONPATH_DO_EXTRA_ARGS_IN , to_update, &(struct csonpath_child_info ){}, NULL
#define CSONPATH_DO_EXTRA_DECLATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
#define CSONPATH_DO_EXTRA_DECLARATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
#define CSONPATH_DO_FIND_ALL nb_res += tret;
#define CSONPATH_DO_FILTER_FIND CSONPATH_GOTO_ON_RELOOP(filter_again)

Expand Down Expand Up @@ -1381,18 +1390,20 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
#define CSONPATH_DO_RET_TYPE int
#define CSONPATH_DO_FUNC_NAME callback
#define CSONPATH_DO_RETURN do { \
CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); return 1;} \
while (0)
if (CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata) < 0) \
return -1; \
return 1;} \
while (0)

#define CSONPATH_DO_EXTRA_ARGS_FIND_ALL , callback, udata, child_info
#define CSONPATH_DO_EXTRA_ARGS_NEESTED , callback, udata, \
csonpath_child_info_set(child_info, tmp, (intptr_t)key_idx)
#define CSONPATH_DO_EXTRA_ARGS , CSONPATH_CALLBACK callback, CSONPATH_CALLBACK_DATA udata
#define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, &(struct csonpath_child_info ){}
#define CSONPATH_DO_EXTRA_DECLATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info
#define CSONPATH_DO_EXTRA_DECLARATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info

#define CSONPATH_DO_FIND_ALL nb_res += tret;
#define CSONPATH_DO_FILTER_FIND nb_res += tret;
#define CSONPATH_DO_FIND_ALL do { if (tret < 0) return tret; nb_res += tret; } while (0)
#define CSONPATH_DO_FILTER_FIND do { if (tret < 0) return tret; nb_res += tret; } while (0)

#define CSONPATH_DO_FIND_ALL_OUT return nb_res;

Expand All @@ -1411,21 +1422,22 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
#define CSONPATH_DO_RET_TYPE int
#define CSONPATH_DO_FUNC_NAME update_or_create_callback
#define CSONPATH_DO_RETURN \
if (tmp == value) { \
*need_reloop = 1; \
} \
CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); \
return 1;
if (need_reloop && tmp == value) { \
*need_reloop = 1; \
} \
if (CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata) < 0) \
return -1; \
return 1;

#define CSONPATH_DO_EXTRA_ARGS_FIND_ALL , callback, udata, NULL, need_reloop
#define CSONPATH_DO_EXTRA_ARGS_NEESTED , callback, udata, \
#define CSONPATH_DO_EXTRA_ARGS_NEESTED , callback, udata, \
csonpath_child_info_set(&(struct csonpath_child_info ){}, tmp, (intptr_t)key_idx), \
&need_reloop_in
#define CSONPATH_DO_EXTRA_ARGS , CSONPATH_CALLBACK callback, CSONPATH_CALLBACK_DATA udata
#define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, &(struct csonpath_child_info ){}, NULL
#define CSONPATH_DO_EXTRA_DECLATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
#define CSONPATH_DO_FIND_ALL nb_res += tret;
#define CSONPATH_DO_FILTER_FIND CSONPATH_GOTO_ON_RELOOP(filter_again)
#define CSONPATH_DO_EXTRA_DECLARATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
#define CSONPATH_DO_FIND_ALL do { if (tret < 0) return tret; nb_res += tret; } while (0)
#define CSONPATH_DO_FILTER_FIND do { if (tret < 0) return tret; CSONPATH_GOTO_ON_RELOOP(filter_again); } while (0)

#define CSONPATH_DO_FIND_ALL_PRE_LOOP int need_reloop_in = 0;

Expand All @@ -1434,7 +1446,7 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
#define CSONPATH_DO_FIND_ALL_OUT return nb_res;

#define CSONPATH_PRE_GET_ROOT \
int to_check = *walker; \
int to_check = walker[1]; \
if (csonpath_is_endish_inst(to_check)) { \
CSONPATH_GETTER_ERR("can't update root ($)\n"); \
return CSONPATH_NONE_FOUND_RET; \
Expand Down
14 changes: 7 additions & 7 deletions csonpath_do.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
#define CSONPATH_DO_POST_FIND_ARRAY
#endif

#ifndef CSONPATH_DO_EXTRA_DECLATION
#define CSONPATH_DO_EXTRA_DECLATION
#ifndef CSONPATH_DO_EXTRA_DECLARATION
#define CSONPATH_DO_EXTRA_DECLARATION
#endif

#ifndef CSONPATH_DO_FIND_ALL_CLEAUP
Expand Down Expand Up @@ -121,7 +121,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const
CSONPATH_JSON origin,
CSONPATH_JSON value,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLATION);
const char *walker CSONPATH_DO_EXTRA_DECLARATION);


#define csonpath_do_dotdot__(name) CATCAT(csonpath_, name, _dotdot)
Expand All @@ -132,7 +132,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(const struct csonpath cjp[const s
CSONPATH_JSON origin,
CSONPATH_JSON tmp,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLATION)
const char *walker CSONPATH_DO_EXTRA_DECLARATION)
{
CSONPATH_JSON el;
CSONPATH_DO_DECLARATION;
Expand Down Expand Up @@ -181,7 +181,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const
CSONPATH_JSON origin,
CSONPATH_JSON value,
CSONPATH_JSON ctx,
const char *walker CSONPATH_DO_EXTRA_DECLATION)
const char *walker CSONPATH_DO_EXTRA_DECLARATION)
{
CSONPATH_JSON tmp = value;
CSONPATH_DO_DECLARATION;
Expand Down Expand Up @@ -218,7 +218,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const
CSONPATH_JSON el;
int operation_in = *walker, operation = *walker;
const char *owalker;
int filter_next_in = *(walker+1), filter_next = *(walker+1);
int filter_next_in = (unsigned char)*(walker+1), filter_next = (unsigned char)*(walker+1);
const char *next = walker + 2;
int foreach_idx;

Expand Down Expand Up @@ -504,7 +504,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
#undef CSONPATH_DO_EXTRA_ARGS_IN
#undef CSONPATH_DO_EXTRA_ARGS_FIND_ALL
#undef CSONPATH_DO_EXTRA_ARGS
#undef CSONPATH_DO_EXTRA_DECLATION
#undef CSONPATH_DO_EXTRA_DECLARATION
#undef CSONPATH_DO_FIND_ALL_PRE_LOOP
#undef CSONPATH_DO_FOREACH_PRE_SET
#undef CSONPATH_DO_GET_ALL_OUT
Expand Down
2 changes: 1 addition & 1 deletion csonpath_json-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ typedef void (*json_c_callback)(json_object *, struct csonpath_child_info *, jso
#define CSONPATH_CALLBACK_DATA void *

#define CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata) \
callback(ctx, child_info, tmp, udata)
(callback(ctx, child_info, tmp, udata), 0)


#define CSONPATH_NEED_FOREACH_REDO(o) \
Expand Down
48 changes: 41 additions & 7 deletions csonpath_python.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,23 @@

#define CSONPATH_CALLBACK_DATA PyObject *

#define CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata) do { \
#define CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata) \
({ \
int _cb_ok = 0; \
PyObject *arglist; \
PyObject *_cb_ret; \
if (child_info->type == CSONPATH_STR) \
arglist = Py_BuildValue("(OsOO)", ctx, child_info->key, tmp, udata); \
else \
arglist = Py_BuildValue("(OiOO)", ctx, child_info->idx, tmp, udata); \
PyObject_CallObject(callback, arglist); \
_cb_ret = PyObject_CallObject(callback, arglist); \
Py_DECREF(arglist); \
} while (0)
if (!_cb_ret) \
_cb_ok = -1; \
else \
Py_DECREF(_cb_ret); \
_cb_ok; \
})

/* assuming each modification of the object need to go out of the loop */
#define CSONPATH_NEED_FOREACH_REDO(o) 1
Expand Down Expand Up @@ -107,6 +115,10 @@ static int pydict_try_setitemstring(PyObject *obj, const char * const at, PyObj
Py_XDECREF(str);
return -1;
}
if (!at) {
PyErr_SetString(PyExc_TypeError, "dict keys must be strings");
return -1;
}
PyDict_SetItemString(obj, at, el);
return 1;
}
Expand Down Expand Up @@ -193,6 +205,11 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
CSONPATH_PRAGMA("GCC unroll 8") \
for (intptr_t key_idx = 0; key_idx < array_len_; ++key_idx) { \
el = PyList_GetItem(obj, key_idx); \
if (!el) { \
PyErr_SetString(PyExc_RuntimeError, \
"list was modified during iteration"); \
break; \
} \
code \
} \
}
Expand Down Expand Up @@ -298,6 +315,10 @@ static PyObject *find_first(PyCsonPathObject *self, PyObject* args)

static PyObject *print_instructions(PyCsonPathObject *self, PyObject *args, PyObject *kwds)
{
if (!self->cp) {
PyErr_SetString(PyExc_RuntimeError, "compiled path is NULL");
return NULL;
}
csonpath_print_instruction(self->cp);
Py_RETURN_NONE;
}
Expand All @@ -309,8 +330,9 @@ static PyObject *callback(PyCsonPathObject *self, PyObject* args)
if (!PyArg_ParseTuple(args, "OO|O", &json, &callback, &udata))
BAD_ARG();
int ret = csonpath_callback(self->cp, json, callback, udata);
if (PyErr_Occurred())
if (PyErr_Occurred() || ret < 0) {
return NULL;
}
return PyLong_FromLong(ret);
}

Expand All @@ -321,7 +343,7 @@ static PyObject *do_remove(PyCsonPathObject *self, PyObject* args)
if (!PyArg_ParseTuple(args, "O", &json))
BAD_ARG();
int ret = csonpath_remove(self->cp, json);
if (PyErr_Occurred())
if (PyErr_Occurred() || ret < 0)
return NULL;
return PyLong_FromLong(ret);
}
Expand Down Expand Up @@ -365,10 +387,22 @@ static void PyCsonPath_dealloc(PyCsonPathObject *self) {
static PyObject *PyCsonPath_set_path(PyCsonPathObject *self, PyObject* args) {
const char *new_path;
if (!PyArg_ParseTuple(args, "s", &new_path))
return Py_False;
return NULL;
if (!new_path) return Py_False;

self->cp = csonpath_set_path(self->cp, new_path);
struct csonpath *new_cjp = csonpath_new_ex(new_path, CSONPATH_NO_DETROY);
if (!new_cjp) {
PyErr_NoMemory();
return NULL;
}
if (new_cjp->compile_error) {
PyErr_Format(PyExc_ValueError, "compilation fail %s",
new_cjp->compile_error);
csonpath_destroy(new_cjp);
return NULL;
}
csonpath_destroy(self->cp);
self->cp = new_cjp;
return Py_True;
}

Expand Down
Loading
Loading