csonpath 0.15.0__tar.gz → 0.17.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {csonpath-0.15.0 → csonpath-0.17.0}/Makefile +22 -4
  2. {csonpath-0.15.0/csonpath.egg-info → csonpath-0.17.0}/PKG-INFO +100 -3
  3. {csonpath-0.15.0 → csonpath-0.17.0}/README.md +99 -2
  4. {csonpath-0.15.0 → csonpath-0.17.0}/configure +5 -0
  5. {csonpath-0.15.0 → csonpath-0.17.0/csonpath.egg-info}/PKG-INFO +100 -3
  6. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath.egg-info/SOURCES.txt +1 -0
  7. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath.h +133 -69
  8. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath_do.h +9 -9
  9. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath_json-c.h +21 -9
  10. csonpath-0.17.0/csonpath_my_fuzzing.h +440 -0
  11. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath_python.c +168 -30
  12. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath_yyjson.h +5 -3
  13. {csonpath-0.15.0 → csonpath-0.17.0}/pyproject.toml +2 -2
  14. {csonpath-0.15.0 → csonpath-0.17.0}/LICENSE +0 -0
  15. {csonpath-0.15.0 → csonpath-0.17.0}/MANIFEST.in +0 -0
  16. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath.egg-info/dependency_links.txt +0 -0
  17. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath.egg-info/requires.txt +0 -0
  18. {csonpath-0.15.0 → csonpath-0.17.0}/csonpath.egg-info/top_level.txt +0 -0
  19. {csonpath-0.15.0 → csonpath-0.17.0}/setup.cfg +0 -0
  20. {csonpath-0.15.0 → csonpath-0.17.0}/setup.py +0 -0
  21. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/.git +0 -0
  22. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/.github/workflows/c-cpp.yml +0 -0
  23. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/.gitignore +0 -0
  24. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/LICENSE +0 -0
  25. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/Makefile +0 -0
  26. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/README.md +0 -0
  27. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/clib.json +0 -0
  28. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/formal_verification.md +0 -0
  29. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/re.c +0 -0
  30. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/re.h +0 -0
  31. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/scripts/exrex.py +0 -0
  32. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/scripts/regex_test.py +0 -0
  33. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/scripts/regex_test_neg.py +0 -0
  34. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test1.c +0 -0
  35. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test2.c +0 -0
  36. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test3.c +0 -0
  37. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test_compile.c +0 -0
  38. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test_print.c +0 -0
  39. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test_rand.c +0 -0
  40. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test_rand_neg.c +0 -0
  41. {csonpath-0.15.0 → csonpath-0.17.0}/tiny-regex-c/tests/test_thread.c +0 -0
@@ -5,7 +5,7 @@ YYJSON_LDFLAGS=$(shell pkg-config --libs yyjson)
5
5
 
6
6
  include config.mk
7
7
 
8
- 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
8
+ 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 test-json-crash-vectors test-json-my-fuzz
9
9
 
10
10
  YYJSON_TESTS=test-yyjson
11
11
 
@@ -15,7 +15,7 @@ bench:
15
15
  bench-clean:
16
16
  make -C bench clean
17
17
 
18
- .PHONY: all clean tests pip-dev pip-dev bench bench-clean
18
+ .PHONY: all clean tests pip-dev pip-dev bench bench-clean tests-cli
19
19
 
20
20
  CFLAGS+= -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -O0 -g
21
21
 
@@ -43,10 +43,19 @@ test-json-get-array-big-index: tests/json-c/get-array-big-index.c csonpath_json-
43
43
  test-json-union: tests/json-c/union.c csonpath_json-c.h csonpath.h csonpath_do.h
44
44
  $(CC) tests/json-c/union.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-union $(JSON_C_LDFLAGS) $(LDFLAGS)
45
45
 
46
+ test-json-audit-bugs: tests/json-c/audit-bugs.c csonpath_json-c.h csonpath.h csonpath_do.h
47
+ $(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)
48
+
49
+ test-json-crash-vectors: tests/json-c/crash-vectors.c csonpath_json-c.h csonpath.h csonpath_do.h
50
+ $(CC) tests/json-c/crash-vectors.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-crash-vectors $(JSON_C_LDFLAGS) $(LDFLAGS)
51
+
52
+ test-json-my-fuzz: tests/json-c/my_fuzz.c csonpath_json-c.h csonpath_my_fuzzing.h csonpath.h csonpath_do.h
53
+ $(CC) tests/json-c/my_fuzz.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-json-my-fuzz $(JSON_C_LDFLAGS) $(LDFLAGS)
54
+
46
55
  test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do.h
47
56
  $(CC) tests/yyjson/test-yyjson.c $(EXTRA_FILES) $(YYJSON_CFLAGS) $(CFLAGS) -Wno-format -I./ -o test-yyjson $(YYJSON_LDFLAGS) $(LDFLAGS)
48
57
 
49
- 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
58
+ 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-json-crash-vectors test-yyjson test-json-my-fuzz
50
59
  ./test-json-c-get-a
51
60
  ./test-json-update
52
61
  ./test-json-filter
@@ -55,7 +64,16 @@ test-yyjson: tests/yyjson/test-yyjson.c csonpath_yyjson.h csonpath.h csonpath_do
55
64
  ./test-json-filter-and-missing-key
56
65
  ./test-json-get-array-big-index
57
66
  ./test-json-union
67
+ ./test-json-audit-bugs
68
+ ./test-json-crash-vectors
58
69
  ./test-yyjson
70
+ ./test-json-my-fuzz
71
+
72
+ csonpath: cli/csonpath_cli.c csonpath_json-c.h csonpath.h csonpath_do.h
73
+ $(CC) cli/csonpath_cli.c $(EXTRA_FILES) $(JSON_C_CFLAGS) $(CFLAGS) -I./ -o csonpath $(JSON_C_LDFLAGS) $(LDFLAGS)
74
+
75
+ tests-cli: csonpath
76
+ bash tests/cli/run.sh
59
77
 
60
78
  pip-dev:
61
79
  pip install -e .[dev] --force-reinstall
@@ -66,5 +84,5 @@ tests-py: pip-dev
66
84
  tests: tests-py tests-c
67
85
 
68
86
  clean:
69
- 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
87
+ 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-json-crash-vectors test-yyjson test-json-my-fuzz csonpath
70
88
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -15,7 +15,7 @@ Dynamic: license-file
15
15
 
16
16
  **csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
17
17
 
18
- Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c) and Python are provided.
18
+ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c), [yyjson](https://github.com/ibireme/yyjson), Python and Rust (via `serde_json`) are provided.
19
19
 
20
20
  ---
21
21
 
@@ -30,7 +30,8 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
30
30
  | Array index | `$.array[0]` | Access by zero-based index |
31
31
  | Wildcard `[*]` | `$.array[*].field` | Iterate all array elements |
32
32
  | Recursive descent `..` | `$..name` | Search recursively for a key |
33
- | Union `\|` / `,` | `$.a \| $.b` or `$['a','b']` | Match multiple paths at once |
33
+ | Union `,` (inside brackets) | `$['a','b']`, `$.array[0,1]`, `$.items[?n==1, ?n==2]` | Match all listed selectors at once |
34
+ | OR fallback `\|` | `$.a \| $.b` | Try the left path first; fall back to the right one if it does not match. Only the first successful path is used. |
34
35
  | Filters | `$.items[?price > 10]` | Filter array elements |
35
36
  | Regex filters | `$.items[?name =~ "foo"]` | POSIX regex-based filtering |
36
37
  | Multiple filters (`&`) | `$.items[?a=1 & b=2]` | Combine conditions |
@@ -61,6 +62,7 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
61
62
  - [Usage](#-usage)
62
63
  - [C API Reference](#-c-api-reference)
63
64
  - [Python API Reference](#-python-api-reference)
65
+ - [CLI](#%EF%B8%8F-cli)
64
66
  - [Custom Backends](#-custom-backends)
65
67
  - [Running Tests](#-running-tests)
66
68
  - [Directory Structure](#-directory-structure)
@@ -86,6 +88,20 @@ Make sure to link against `json-c` when compiling:
86
88
  gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
87
89
  ```
88
90
 
91
+ ### C (Rust backend)
92
+ The Rust backend is located in `rust/`. It builds both a safe Rust API and the C glue required by the csonpath core.
93
+
94
+ ```sh
95
+ cd rust
96
+ cargo build
97
+ cargo test
98
+ ```
99
+
100
+ To use it from C, include the backend header and link against the produced static library:
101
+ ```c
102
+ #include "rust/csonpath_rust_backend.h"
103
+ ```
104
+
89
105
  ### Python
90
106
  Install from PyPI:
91
107
  ```sh
@@ -251,6 +267,76 @@ Free the csonpath object.
251
267
 
252
268
  ---
253
269
 
270
+ ## 🖥️ CLI
271
+
272
+ A standalone C CLI is available in `cli/csonpath_cli.c`. It links directly against `json-c` and the csonpath C core, so it works without Python.
273
+
274
+ ```sh
275
+ make csonpath # build ./csonpath
276
+ make tests-cli # run shell tests
277
+ ```
278
+
279
+ It reads JSON from stdin, a file (`-f`), or a string (`-s`) and exposes the library operations through action flags.
280
+
281
+ ```sh
282
+ # Get the first match (default)
283
+ echo '{"a": "value", "array": [1, 2, 3]}' | ./csonpath '$.a'
284
+ # => "value"
285
+
286
+ # Find all matches
287
+ echo '{"items": [{"price": 5}, {"price": 15}]}' | ./csonpath -a '$.items[?price > 10]'
288
+ # => [{"price":15}]
289
+
290
+ # One match per line
291
+ echo '{"array": [1, 2, 3]}' | ./csonpath -a -o lines '$.array[*]'
292
+ # => 1
293
+ # => 2
294
+ # => 3
295
+
296
+ # Set or create a value
297
+ echo '{"a": 1}' | ./csonpath --set '42' '$.x.y.z'
298
+ # => {"a":1,"x":{"y":{"z":42}}}
299
+
300
+ # Or with a positional value
301
+ echo '{"a": 1}' | ./csonpath '$.x.y.z' '42'
302
+
303
+ # Remove matches
304
+ echo '{"a": 1, "b": 2}' | ./csonpath -d '$.b'
305
+ # => {"a":1}
306
+
307
+ # Edit a file in place
308
+ ./csonpath -f data.json -p -i --set '"2.0"' '$.version'
309
+ ```
310
+
311
+ ### Options
312
+
313
+ | Option | Description |
314
+ |---|---|
315
+ | `-a`, `--all` | Return all matches instead of the first one. |
316
+ | `-d`, `--delete` | Remove matches and print the modified JSON. |
317
+ | `--set VALUE` | Set `PATH` to `VALUE` (JSON). |
318
+ | `VALUE` (positional) | Alternative to `--set`. |
319
+ | `-r`, `--raw` | Treat the value as a raw string. |
320
+ | `-i`, `--in-place` | Edit `FILE` in place (requires `--file`). |
321
+ | `--strict` | Exit with an error if `--delete` removes nothing. |
322
+ | `-f FILE`, `--file FILE` | Read JSON from `FILE` instead of stdin. |
323
+ | `-s JSON`, `--string JSON` | Read JSON from a string. |
324
+ | `-j`, `--jq-like` | Allow jq-style paths without a leading `$`. |
325
+ | `-p`, `--pretty` | Pretty-print JSON output. |
326
+ | `-o {json,pretty,raw,lines}` | Output format (default: `json`). |
327
+ | `-e`, `--empty-array` | Return `[]` instead of nothing when `-a` matches nothing. |
328
+
329
+ ### Exit codes
330
+
331
+ | Code | Meaning |
332
+ |---|---|
333
+ | `0` | Success. |
334
+ | `1` | No match found, or `--strict` delete found nothing. |
335
+ | `EINVAL` | Usage error, JSON parse error, JSONPath compilation error, or invalid JSON value. |
336
+ | `errno` | I/O error (e.g. `ENOENT`, `EACCES`). |
337
+
338
+ ---
339
+
254
340
  ## 🔌 Custom Backends
255
341
 
256
342
  csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
@@ -259,7 +345,9 @@ To create a custom backend, define the required macros and types in a header fil
259
345
 
260
346
  For more details, see the existing backend implementations:
261
347
  - `csonpath_json-c.h` — json-c backend
348
+ - `csonpath_yyjson.h` — yyjson backend
262
349
  - `csonpath_python.c` — Python backend
350
+ - `rust/csonpath_rust_backend.h` — Rust / serde_json backend
263
351
 
264
352
  ---
265
353
 
@@ -270,6 +358,12 @@ For more details, see the existing backend implementations:
270
358
  make tests-c
271
359
  ```
272
360
 
361
+ ### Rust Tests
362
+ ```sh
363
+ cd rust
364
+ cargo test
365
+ ```
366
+
273
367
  ### Python Tests
274
368
  ```sh
275
369
  make tests-py
@@ -288,7 +382,10 @@ make tests
288
382
  |---|---|
289
383
  | `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
290
384
  | `csonpath_json-c.h` | json-c backend |
385
+ | `csonpath_yyjson.h` | yyjson backend |
291
386
  | `csonpath_python.c` | Python C extension backend |
387
+ | `rust/` | Rust backend (safe API, FFI, C glue) |
388
+ | `csonpath_my_fuzzing.h` | Fuzzer helpers (C) |
292
389
  | `tests/` | C and Python test suites |
293
390
  | `bench/` | Performance benchmarks |
294
391
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  **csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
8
8
 
9
- Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c) and Python are provided.
9
+ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c), [yyjson](https://github.com/ibireme/yyjson), Python and Rust (via `serde_json`) are provided.
10
10
 
11
11
  ---
12
12
 
@@ -21,7 +21,8 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
21
21
  | Array index | `$.array[0]` | Access by zero-based index |
22
22
  | Wildcard `[*]` | `$.array[*].field` | Iterate all array elements |
23
23
  | Recursive descent `..` | `$..name` | Search recursively for a key |
24
- | Union `\|` / `,` | `$.a \| $.b` or `$['a','b']` | Match multiple paths at once |
24
+ | Union `,` (inside brackets) | `$['a','b']`, `$.array[0,1]`, `$.items[?n==1, ?n==2]` | Match all listed selectors at once |
25
+ | OR fallback `\|` | `$.a \| $.b` | Try the left path first; fall back to the right one if it does not match. Only the first successful path is used. |
25
26
  | Filters | `$.items[?price > 10]` | Filter array elements |
26
27
  | Regex filters | `$.items[?name =~ "foo"]` | POSIX regex-based filtering |
27
28
  | Multiple filters (`&`) | `$.items[?a=1 & b=2]` | Combine conditions |
@@ -52,6 +53,7 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
52
53
  - [Usage](#-usage)
53
54
  - [C API Reference](#-c-api-reference)
54
55
  - [Python API Reference](#-python-api-reference)
56
+ - [CLI](#%EF%B8%8F-cli)
55
57
  - [Custom Backends](#-custom-backends)
56
58
  - [Running Tests](#-running-tests)
57
59
  - [Directory Structure](#-directory-structure)
@@ -77,6 +79,20 @@ Make sure to link against `json-c` when compiling:
77
79
  gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
78
80
  ```
79
81
 
82
+ ### C (Rust backend)
83
+ The Rust backend is located in `rust/`. It builds both a safe Rust API and the C glue required by the csonpath core.
84
+
85
+ ```sh
86
+ cd rust
87
+ cargo build
88
+ cargo test
89
+ ```
90
+
91
+ To use it from C, include the backend header and link against the produced static library:
92
+ ```c
93
+ #include "rust/csonpath_rust_backend.h"
94
+ ```
95
+
80
96
  ### Python
81
97
  Install from PyPI:
82
98
  ```sh
@@ -242,6 +258,76 @@ Free the csonpath object.
242
258
 
243
259
  ---
244
260
 
261
+ ## 🖥️ CLI
262
+
263
+ A standalone C CLI is available in `cli/csonpath_cli.c`. It links directly against `json-c` and the csonpath C core, so it works without Python.
264
+
265
+ ```sh
266
+ make csonpath # build ./csonpath
267
+ make tests-cli # run shell tests
268
+ ```
269
+
270
+ It reads JSON from stdin, a file (`-f`), or a string (`-s`) and exposes the library operations through action flags.
271
+
272
+ ```sh
273
+ # Get the first match (default)
274
+ echo '{"a": "value", "array": [1, 2, 3]}' | ./csonpath '$.a'
275
+ # => "value"
276
+
277
+ # Find all matches
278
+ echo '{"items": [{"price": 5}, {"price": 15}]}' | ./csonpath -a '$.items[?price > 10]'
279
+ # => [{"price":15}]
280
+
281
+ # One match per line
282
+ echo '{"array": [1, 2, 3]}' | ./csonpath -a -o lines '$.array[*]'
283
+ # => 1
284
+ # => 2
285
+ # => 3
286
+
287
+ # Set or create a value
288
+ echo '{"a": 1}' | ./csonpath --set '42' '$.x.y.z'
289
+ # => {"a":1,"x":{"y":{"z":42}}}
290
+
291
+ # Or with a positional value
292
+ echo '{"a": 1}' | ./csonpath '$.x.y.z' '42'
293
+
294
+ # Remove matches
295
+ echo '{"a": 1, "b": 2}' | ./csonpath -d '$.b'
296
+ # => {"a":1}
297
+
298
+ # Edit a file in place
299
+ ./csonpath -f data.json -p -i --set '"2.0"' '$.version'
300
+ ```
301
+
302
+ ### Options
303
+
304
+ | Option | Description |
305
+ |---|---|
306
+ | `-a`, `--all` | Return all matches instead of the first one. |
307
+ | `-d`, `--delete` | Remove matches and print the modified JSON. |
308
+ | `--set VALUE` | Set `PATH` to `VALUE` (JSON). |
309
+ | `VALUE` (positional) | Alternative to `--set`. |
310
+ | `-r`, `--raw` | Treat the value as a raw string. |
311
+ | `-i`, `--in-place` | Edit `FILE` in place (requires `--file`). |
312
+ | `--strict` | Exit with an error if `--delete` removes nothing. |
313
+ | `-f FILE`, `--file FILE` | Read JSON from `FILE` instead of stdin. |
314
+ | `-s JSON`, `--string JSON` | Read JSON from a string. |
315
+ | `-j`, `--jq-like` | Allow jq-style paths without a leading `$`. |
316
+ | `-p`, `--pretty` | Pretty-print JSON output. |
317
+ | `-o {json,pretty,raw,lines}` | Output format (default: `json`). |
318
+ | `-e`, `--empty-array` | Return `[]` instead of nothing when `-a` matches nothing. |
319
+
320
+ ### Exit codes
321
+
322
+ | Code | Meaning |
323
+ |---|---|
324
+ | `0` | Success. |
325
+ | `1` | No match found, or `--strict` delete found nothing. |
326
+ | `EINVAL` | Usage error, JSON parse error, JSONPath compilation error, or invalid JSON value. |
327
+ | `errno` | I/O error (e.g. `ENOENT`, `EACCES`). |
328
+
329
+ ---
330
+
245
331
  ## 🔌 Custom Backends
246
332
 
247
333
  csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
@@ -250,7 +336,9 @@ To create a custom backend, define the required macros and types in a header fil
250
336
 
251
337
  For more details, see the existing backend implementations:
252
338
  - `csonpath_json-c.h` — json-c backend
339
+ - `csonpath_yyjson.h` — yyjson backend
253
340
  - `csonpath_python.c` — Python backend
341
+ - `rust/csonpath_rust_backend.h` — Rust / serde_json backend
254
342
 
255
343
  ---
256
344
 
@@ -261,6 +349,12 @@ For more details, see the existing backend implementations:
261
349
  make tests-c
262
350
  ```
263
351
 
352
+ ### Rust Tests
353
+ ```sh
354
+ cd rust
355
+ cargo test
356
+ ```
357
+
264
358
  ### Python Tests
265
359
  ```sh
266
360
  make tests-py
@@ -279,7 +373,10 @@ make tests
279
373
  |---|---|
280
374
  | `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
281
375
  | `csonpath_json-c.h` | json-c backend |
376
+ | `csonpath_yyjson.h` | yyjson backend |
282
377
  | `csonpath_python.c` | Python C extension backend |
378
+ | `rust/` | Rust backend (safe API, FFI, C glue) |
379
+ | `csonpath_my_fuzzing.h` | Fuzzer helpers (C) |
283
380
  | `tests/` | C and Python test suites |
284
381
  | `bench/` | Performance benchmarks |
285
382
 
@@ -21,12 +21,17 @@ for arg in $@; do
21
21
  CFLAGS="${CFLAGS} -DCSONPATH_PCRE2_POSIX $(pkg-config --cflags libpcre2-posix)"
22
22
  LDFLAGS="${LDFLAGS} $(pkg-config --libs libpcre2-posix)"
23
23
  fi
24
+ if [ "--asan" = $arg ]; then
25
+ CFLAGS="${CFLAGS} -fsanitize=address -fno-omit-frame-pointer"
26
+ LDFLAGS="${LDFLAGS} -fsanitize=address"
27
+ fi
24
28
  if [ "--help" = $arg ]; then
25
29
  echo "help"
26
30
  echo " --tiny-regex"
27
31
  echo " --pcre2-regex"
28
32
  echo " --pcre2-posix"
29
33
  echo " --no-regex"
34
+ echo " --asan"
30
35
  fi
31
36
  done
32
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.15.0
3
+ Version: 0.17.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -15,7 +15,7 @@ Dynamic: license-file
15
15
 
16
16
  **csonpath** is a partial [JSONPath](https://goessner.net/articles/JsonPath/) implementation in C, with Python bindings. It allows you to query, update, and remove data from JSON objects using path expressions.
17
17
 
18
- Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c) and Python are provided.
18
+ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work with any C library or environment that manipulates array, object, and scalar types—not just JSON. Out of the box, backends for [json-c](https://github.com/json-c/json-c), [yyjson](https://github.com/ibireme/yyjson), Python and Rust (via `serde_json`) are provided.
19
19
 
20
20
  ---
21
21
 
@@ -30,7 +30,8 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
30
30
  | Array index | `$.array[0]` | Access by zero-based index |
31
31
  | Wildcard `[*]` | `$.array[*].field` | Iterate all array elements |
32
32
  | Recursive descent `..` | `$..name` | Search recursively for a key |
33
- | Union `\|` / `,` | `$.a \| $.b` or `$['a','b']` | Match multiple paths at once |
33
+ | Union `,` (inside brackets) | `$['a','b']`, `$.array[0,1]`, `$.items[?n==1, ?n==2]` | Match all listed selectors at once |
34
+ | OR fallback `\|` | `$.a \| $.b` | Try the left path first; fall back to the right one if it does not match. Only the first successful path is used. |
34
35
  | Filters | `$.items[?price > 10]` | Filter array elements |
35
36
  | Regex filters | `$.items[?name =~ "foo"]` | POSIX regex-based filtering |
36
37
  | Multiple filters (`&`) | `$.items[?a=1 & b=2]` | Combine conditions |
@@ -61,6 +62,7 @@ Unlike many JSONPath libraries, csonpath is **backend-agnostic**: it can work wi
61
62
  - [Usage](#-usage)
62
63
  - [C API Reference](#-c-api-reference)
63
64
  - [Python API Reference](#-python-api-reference)
65
+ - [CLI](#%EF%B8%8F-cli)
64
66
  - [Custom Backends](#-custom-backends)
65
67
  - [Running Tests](#-running-tests)
66
68
  - [Directory Structure](#-directory-structure)
@@ -86,6 +88,20 @@ Make sure to link against `json-c` when compiling:
86
88
  gcc myapp.c -o myapp $(pkg-config --cflags --libs json-c)
87
89
  ```
88
90
 
91
+ ### C (Rust backend)
92
+ The Rust backend is located in `rust/`. It builds both a safe Rust API and the C glue required by the csonpath core.
93
+
94
+ ```sh
95
+ cd rust
96
+ cargo build
97
+ cargo test
98
+ ```
99
+
100
+ To use it from C, include the backend header and link against the produced static library:
101
+ ```c
102
+ #include "rust/csonpath_rust_backend.h"
103
+ ```
104
+
89
105
  ### Python
90
106
  Install from PyPI:
91
107
  ```sh
@@ -251,6 +267,76 @@ Free the csonpath object.
251
267
 
252
268
  ---
253
269
 
270
+ ## 🖥️ CLI
271
+
272
+ A standalone C CLI is available in `cli/csonpath_cli.c`. It links directly against `json-c` and the csonpath C core, so it works without Python.
273
+
274
+ ```sh
275
+ make csonpath # build ./csonpath
276
+ make tests-cli # run shell tests
277
+ ```
278
+
279
+ It reads JSON from stdin, a file (`-f`), or a string (`-s`) and exposes the library operations through action flags.
280
+
281
+ ```sh
282
+ # Get the first match (default)
283
+ echo '{"a": "value", "array": [1, 2, 3]}' | ./csonpath '$.a'
284
+ # => "value"
285
+
286
+ # Find all matches
287
+ echo '{"items": [{"price": 5}, {"price": 15}]}' | ./csonpath -a '$.items[?price > 10]'
288
+ # => [{"price":15}]
289
+
290
+ # One match per line
291
+ echo '{"array": [1, 2, 3]}' | ./csonpath -a -o lines '$.array[*]'
292
+ # => 1
293
+ # => 2
294
+ # => 3
295
+
296
+ # Set or create a value
297
+ echo '{"a": 1}' | ./csonpath --set '42' '$.x.y.z'
298
+ # => {"a":1,"x":{"y":{"z":42}}}
299
+
300
+ # Or with a positional value
301
+ echo '{"a": 1}' | ./csonpath '$.x.y.z' '42'
302
+
303
+ # Remove matches
304
+ echo '{"a": 1, "b": 2}' | ./csonpath -d '$.b'
305
+ # => {"a":1}
306
+
307
+ # Edit a file in place
308
+ ./csonpath -f data.json -p -i --set '"2.0"' '$.version'
309
+ ```
310
+
311
+ ### Options
312
+
313
+ | Option | Description |
314
+ |---|---|
315
+ | `-a`, `--all` | Return all matches instead of the first one. |
316
+ | `-d`, `--delete` | Remove matches and print the modified JSON. |
317
+ | `--set VALUE` | Set `PATH` to `VALUE` (JSON). |
318
+ | `VALUE` (positional) | Alternative to `--set`. |
319
+ | `-r`, `--raw` | Treat the value as a raw string. |
320
+ | `-i`, `--in-place` | Edit `FILE` in place (requires `--file`). |
321
+ | `--strict` | Exit with an error if `--delete` removes nothing. |
322
+ | `-f FILE`, `--file FILE` | Read JSON from `FILE` instead of stdin. |
323
+ | `-s JSON`, `--string JSON` | Read JSON from a string. |
324
+ | `-j`, `--jq-like` | Allow jq-style paths without a leading `$`. |
325
+ | `-p`, `--pretty` | Pretty-print JSON output. |
326
+ | `-o {json,pretty,raw,lines}` | Output format (default: `json`). |
327
+ | `-e`, `--empty-array` | Return `[]` instead of nothing when `-a` matches nothing. |
328
+
329
+ ### Exit codes
330
+
331
+ | Code | Meaning |
332
+ |---|---|
333
+ | `0` | Success. |
334
+ | `1` | No match found, or `--strict` delete found nothing. |
335
+ | `EINVAL` | Usage error, JSON parse error, JSONPath compilation error, or invalid JSON value. |
336
+ | `errno` | I/O error (e.g. `ENOENT`, `EACCES`). |
337
+
338
+ ---
339
+
254
340
  ## 🔌 Custom Backends
255
341
 
256
342
  csonpath is designed to be backend-agnostic. It can work with any data structure that supports array, object, and scalar semantics.
@@ -259,7 +345,9 @@ To create a custom backend, define the required macros and types in a header fil
259
345
 
260
346
  For more details, see the existing backend implementations:
261
347
  - `csonpath_json-c.h` — json-c backend
348
+ - `csonpath_yyjson.h` — yyjson backend
262
349
  - `csonpath_python.c` — Python backend
350
+ - `rust/csonpath_rust_backend.h` — Rust / serde_json backend
263
351
 
264
352
  ---
265
353
 
@@ -270,6 +358,12 @@ For more details, see the existing backend implementations:
270
358
  make tests-c
271
359
  ```
272
360
 
361
+ ### Rust Tests
362
+ ```sh
363
+ cd rust
364
+ cargo test
365
+ ```
366
+
273
367
  ### Python Tests
274
368
  ```sh
275
369
  make tests-py
@@ -288,7 +382,10 @@ make tests
288
382
  |---|---|
289
383
  | `csonpath.h`, `csonpath_do.h` | Core implementation (header-only style) |
290
384
  | `csonpath_json-c.h` | json-c backend |
385
+ | `csonpath_yyjson.h` | yyjson backend |
291
386
  | `csonpath_python.c` | Python C extension backend |
387
+ | `rust/` | Rust backend (safe API, FFI, C glue) |
388
+ | `csonpath_my_fuzzing.h` | Fuzzer helpers (C) |
292
389
  | `tests/` | C and Python test suites |
293
390
  | `bench/` | Performance benchmarks |
294
391
 
@@ -6,6 +6,7 @@ configure
6
6
  csonpath.h
7
7
  csonpath_do.h
8
8
  csonpath_json-c.h
9
+ csonpath_my_fuzzing.h
9
10
  csonpath_python.c
10
11
  csonpath_yyjson.h
11
12
  pyproject.toml