csonpath 0.4.0__tar.gz → 0.6.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -35,6 +35,16 @@ Dynamic: license-file
35
35
 
36
36
  ## 🚀 Features
37
37
 
38
+ ### jsonpath
39
+ - support simple path like ex: `"$.a[3]["oui"]`
40
+ - support `..`: `"$..non`
41
+ - support `[*]`: `"$.array[*].obj[*].field"`
42
+ - support filters:
43
+ - with `>` or `<`: `"$.obj[?.field > 123]"`
44
+ - with `=` or '!=': `"$.obj[?.field != "123"]"`
45
+ - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
46
+ - support `|`: `"$.obj | $.otherobj"`
47
+ ### Functions
38
48
  - **Find First**: Retrieve the first value matching a path.
39
49
  - **Find All**: Retrieve all values matching a path.
40
50
  - **Update or Create**: Update values or create new ones according to the path.
@@ -76,8 +86,53 @@ ret = csonpath_find_first(&p, jobj);
76
86
  // ret now points to "value"
77
87
  ```
78
88
 
89
+ #### Avaible functions:
90
+ ```C
91
+ int csonpath_init(struct csonpath cjp[static 1], const char path[static 1])
92
+ ```
93
+ init a csonpath struct
94
+
95
+ ```C
96
+ int csonpath_set_path(struct csonpath cjp[static 1], const char path[static 1])
97
+ ```
98
+ change the path of a struct
99
+
100
+ ```C
101
+ int csonpath_compile(struct csonpath cjp[static 1])
102
+ ```
103
+ compile the path, doesn't need to be called before using it, but can be useful to catch error earlyer.
104
+ ```C
105
+ void csonpath_print_instruction(struct csonpath cjp[static 1])
106
+ ```
107
+ print all instructions once compiled
108
+ ```C
109
+ struct json_object *csonpath_find_first(struct csonpath cjp[static 1], struct json_object *json);
110
+ ```
111
+ Retrieve the first value matching a path
112
+ ```C
113
+ struct json_object *csonpath_find_all(struct csonpath cjp[static 1], struct json_object *json);
114
+ ```
115
+ Retrieve all values matching a path, return need to be free using `json_object_put`
116
+ ```C
117
+ struct json_object *csonpath_remove(struct csonpath cjp[static 1], struct json_object *json);
118
+ ```
119
+ Remove all matching elements from json
120
+ ```C
121
+ struct json_object *csonpath_update_or_create(struct csonpath cjp[static 1], struct json_object *json, struct json_object *new_val)
122
+ ```
123
+ update and push new_val, in json.
124
+ ```C
125
+ struct json_object *csonpath_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
126
+ ```
127
+ call `callback` on each value matching path
128
+ ```C
129
+ struct json_object *csonpath_update_or_create_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
130
+ ```
131
+ like callback, but update json base on the path, along the way.
132
+
79
133
  ### Usage (Python)
80
134
 
135
+ #### Example
81
136
  ```python
82
137
  import csonpath
83
138
 
@@ -111,7 +166,7 @@ To use csonpath with a different data type or library, simply define the require
111
166
  - `csonpath_json-c.h` - Json-C implementation, use it by including "csonpath_json-c.h" directly in your source
112
167
  - `csonpath_python.c` - python implementation, use it like a python lib (so `pip install .`)
113
168
  - `tests/` - Contains tests
114
- - `bench//` - Some benchmarks
169
+ - `bench/` - Some benchmarks
115
170
 
116
171
  ## 🤝 Contributing
117
172
 
@@ -123,4 +178,3 @@ Feel free to open issues or pull requests!
123
178
 
124
179
  ## 📜 License
125
180
  BSD 3-Clause. See [LICENSE](LICENSE).
126
- remimu.h is under the CC0 1.0 Universal, original source is [here](https://github.com/wareya/Remimu)
@@ -26,6 +26,16 @@
26
26
 
27
27
  ## 🚀 Features
28
28
 
29
+ ### jsonpath
30
+ - support simple path like ex: `"$.a[3]["oui"]`
31
+ - support `..`: `"$..non`
32
+ - support `[*]`: `"$.array[*].obj[*].field"`
33
+ - support filters:
34
+ - with `>` or `<`: `"$.obj[?.field > 123]"`
35
+ - with `=` or '!=': `"$.obj[?.field != "123"]"`
36
+ - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
37
+ - support `|`: `"$.obj | $.otherobj"`
38
+ ### Functions
29
39
  - **Find First**: Retrieve the first value matching a path.
30
40
  - **Find All**: Retrieve all values matching a path.
31
41
  - **Update or Create**: Update values or create new ones according to the path.
@@ -67,8 +77,53 @@ ret = csonpath_find_first(&p, jobj);
67
77
  // ret now points to "value"
68
78
  ```
69
79
 
80
+ #### Avaible functions:
81
+ ```C
82
+ int csonpath_init(struct csonpath cjp[static 1], const char path[static 1])
83
+ ```
84
+ init a csonpath struct
85
+
86
+ ```C
87
+ int csonpath_set_path(struct csonpath cjp[static 1], const char path[static 1])
88
+ ```
89
+ change the path of a struct
90
+
91
+ ```C
92
+ int csonpath_compile(struct csonpath cjp[static 1])
93
+ ```
94
+ compile the path, doesn't need to be called before using it, but can be useful to catch error earlyer.
95
+ ```C
96
+ void csonpath_print_instruction(struct csonpath cjp[static 1])
97
+ ```
98
+ print all instructions once compiled
99
+ ```C
100
+ struct json_object *csonpath_find_first(struct csonpath cjp[static 1], struct json_object *json);
101
+ ```
102
+ Retrieve the first value matching a path
103
+ ```C
104
+ struct json_object *csonpath_find_all(struct csonpath cjp[static 1], struct json_object *json);
105
+ ```
106
+ Retrieve all values matching a path, return need to be free using `json_object_put`
107
+ ```C
108
+ struct json_object *csonpath_remove(struct csonpath cjp[static 1], struct json_object *json);
109
+ ```
110
+ Remove all matching elements from json
111
+ ```C
112
+ struct json_object *csonpath_update_or_create(struct csonpath cjp[static 1], struct json_object *json, struct json_object *new_val)
113
+ ```
114
+ update and push new_val, in json.
115
+ ```C
116
+ struct json_object *csonpath_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
117
+ ```
118
+ call `callback` on each value matching path
119
+ ```C
120
+ struct json_object *csonpath_update_or_create_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
121
+ ```
122
+ like callback, but update json base on the path, along the way.
123
+
70
124
  ### Usage (Python)
71
125
 
126
+ #### Example
72
127
  ```python
73
128
  import csonpath
74
129
 
@@ -102,7 +157,7 @@ To use csonpath with a different data type or library, simply define the require
102
157
  - `csonpath_json-c.h` - Json-C implementation, use it by including "csonpath_json-c.h" directly in your source
103
158
  - `csonpath_python.c` - python implementation, use it like a python lib (so `pip install .`)
104
159
  - `tests/` - Contains tests
105
- - `bench//` - Some benchmarks
160
+ - `bench/` - Some benchmarks
106
161
 
107
162
  ## 🤝 Contributing
108
163
 
@@ -114,4 +169,3 @@ Feel free to open issues or pull requests!
114
169
 
115
170
  ## 📜 License
116
171
  BSD 3-Clause. See [LICENSE](LICENSE).
117
- remimu.h is under the CC0 1.0 Universal, original source is [here](https://github.com/wareya/Remimu)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -35,6 +35,16 @@ Dynamic: license-file
35
35
 
36
36
  ## 🚀 Features
37
37
 
38
+ ### jsonpath
39
+ - support simple path like ex: `"$.a[3]["oui"]`
40
+ - support `..`: `"$..non`
41
+ - support `[*]`: `"$.array[*].obj[*].field"`
42
+ - support filters:
43
+ - with `>` or `<`: `"$.obj[?.field > 123]"`
44
+ - with `=` or '!=': `"$.obj[?.field != "123"]"`
45
+ - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
46
+ - support `|`: `"$.obj | $.otherobj"`
47
+ ### Functions
38
48
  - **Find First**: Retrieve the first value matching a path.
39
49
  - **Find All**: Retrieve all values matching a path.
40
50
  - **Update or Create**: Update values or create new ones according to the path.
@@ -76,8 +86,53 @@ ret = csonpath_find_first(&p, jobj);
76
86
  // ret now points to "value"
77
87
  ```
78
88
 
89
+ #### Avaible functions:
90
+ ```C
91
+ int csonpath_init(struct csonpath cjp[static 1], const char path[static 1])
92
+ ```
93
+ init a csonpath struct
94
+
95
+ ```C
96
+ int csonpath_set_path(struct csonpath cjp[static 1], const char path[static 1])
97
+ ```
98
+ change the path of a struct
99
+
100
+ ```C
101
+ int csonpath_compile(struct csonpath cjp[static 1])
102
+ ```
103
+ compile the path, doesn't need to be called before using it, but can be useful to catch error earlyer.
104
+ ```C
105
+ void csonpath_print_instruction(struct csonpath cjp[static 1])
106
+ ```
107
+ print all instructions once compiled
108
+ ```C
109
+ struct json_object *csonpath_find_first(struct csonpath cjp[static 1], struct json_object *json);
110
+ ```
111
+ Retrieve the first value matching a path
112
+ ```C
113
+ struct json_object *csonpath_find_all(struct csonpath cjp[static 1], struct json_object *json);
114
+ ```
115
+ Retrieve all values matching a path, return need to be free using `json_object_put`
116
+ ```C
117
+ struct json_object *csonpath_remove(struct csonpath cjp[static 1], struct json_object *json);
118
+ ```
119
+ Remove all matching elements from json
120
+ ```C
121
+ struct json_object *csonpath_update_or_create(struct csonpath cjp[static 1], struct json_object *json, struct json_object *new_val)
122
+ ```
123
+ update and push new_val, in json.
124
+ ```C
125
+ struct json_object *csonpath_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
126
+ ```
127
+ call `callback` on each value matching path
128
+ ```C
129
+ struct json_object *csonpath_update_or_create_callback(struct csonpath cjp[static 1], struct json_object *json, json_c_callback callback, void *userdata)
130
+ ```
131
+ like callback, but update json base on the path, along the way.
132
+
79
133
  ### Usage (Python)
80
134
 
135
+ #### Example
81
136
  ```python
82
137
  import csonpath
83
138
 
@@ -111,7 +166,7 @@ To use csonpath with a different data type or library, simply define the require
111
166
  - `csonpath_json-c.h` - Json-C implementation, use it by including "csonpath_json-c.h" directly in your source
112
167
  - `csonpath_python.c` - python implementation, use it like a python lib (so `pip install .`)
113
168
  - `tests/` - Contains tests
114
- - `bench//` - Some benchmarks
169
+ - `bench/` - Some benchmarks
115
170
 
116
171
  ## 🤝 Contributing
117
172
 
@@ -123,4 +178,3 @@ Feel free to open issues or pull requests!
123
178
 
124
179
  ## 📜 License
125
180
  BSD 3-Clause. See [LICENSE](LICENSE).
126
- remimu.h is under the CC0 1.0 Universal, original source is [here](https://github.com/wareya/Remimu)
@@ -34,6 +34,8 @@ enum csonpath_instuction_raw {
34
34
  CSONPATH_INST_GET_OBJ,
35
35
  CSONPATH_INST_GET_ARRAY_SMALL,
36
36
  CSONPATH_INST_GET_ARRAY_BIG,
37
+ CSONPATH_INST_FILTER_KEY_SUPERIOR,
38
+ CSONPATH_INST_FILTER_KEY_INFERIOR,
37
39
  CSONPATH_INST_FILTER_KEY_EQ,
38
40
  CSONPATH_INST_FILTER_KEY_NOT_EQ,
39
41
  CSONPATH_INST_FILTER_KEY_REG_EQ,
@@ -54,6 +56,8 @@ CSONPATH_UNUSED static const char *csonpath_instuction_str[] = {
54
56
  "GET_OBJ",
55
57
  "GET_ARRAY_SMALL",
56
58
  "GET_ARRAY_BIG",
59
+ "FILTER_KEY_SUPERIOR",
60
+ "FILTER_KEY_INFERIOR",
57
61
  "FILTER_KEY_EQ",
58
62
  "FILTER_KEY_NOT_EQ",
59
63
  "FILTER_KEY_REG_EQ",
@@ -82,15 +86,11 @@ struct csonpath_instruction {
82
86
  short int next;
83
87
  };
84
88
 
85
- #define CSONPATH_INST_MIN_ALLOC (1 << 7)
86
-
87
89
  struct csonpath {
88
- char *path;
89
90
  char *compile_error;
91
+ char *path;
90
92
  struct csonpath_instruction *inst_lst;
91
93
  int compiled;
92
- int inst_idx;
93
- int inst_size;
94
94
  #ifndef CSONPATH_NO_REGEX
95
95
  int regex_cnt;
96
96
  regex_t *regexs;
@@ -165,11 +165,26 @@ static inline void csonpath_destroy(struct csonpath cjp[static 1])
165
165
  *cjp = (struct csonpath){};
166
166
  }
167
167
 
168
+ static _Bool csonpath_is_one_char_instruction(int c)
169
+ {
170
+ return c == '|' || c == '$';
171
+ }
172
+
168
173
  static inline int csonpath_init(struct csonpath cjp[static 1],
169
174
  const char path[static 1]) {
175
+ /*
176
+ * We overalloc, but this enable us to avoid checking size,
177
+ * as the only instruction that require 1 character is $, and $$ is not allow
178
+ * we can safely assume that we can't have more instructions than path len / 2 + 2
179
+ * we add plus 2, because "$", is a valid path, and contain 2 instruction: ROOT and END
180
+ */
181
+ int max_inst = strlen(path) / 2 + 1;
182
+ for (const char *cpy = path; *cpy; ++cpy) {
183
+ if (csonpath_is_one_char_instruction(*cpy))
184
+ ++max_inst;
185
+ }
170
186
  *cjp = (struct csonpath) {.path=strdup(path),
171
- .inst_size = CSONPATH_INST_MIN_ALLOC,
172
- .inst_lst = malloc(sizeof(*cjp->inst_lst) * CSONPATH_INST_MIN_ALLOC)};
187
+ .inst_lst = malloc(sizeof(*cjp->inst_lst) * max_inst)};
173
188
  if (!cjp->path || !cjp->inst_lst) {
174
189
  return -ENOMEM;
175
190
  }
@@ -183,27 +198,18 @@ static inline int csonpath_set_path(struct csonpath cjp[static 1],
183
198
  return csonpath_init(cjp, path);
184
199
  }
185
200
 
186
- static inline void csonpath_push_inst(struct csonpath cjp[static 1], int inst)
201
+ static inline void csonpath_push_inst(struct csonpath cjp[static 1], int inst, int *inst_idx)
187
202
  {
188
- if (cjp->inst_idx + 1 > cjp->inst_size) {
189
- cjp->inst_size = cjp->inst_size << 1;
190
- cjp->inst_lst = realloc(cjp->inst_lst, cjp->inst_size);
191
- assert(cjp->inst_lst);
192
- }
193
- cjp->inst_lst[cjp->inst_idx] = (struct csonpath_instruction){.inst=inst};
194
- ++cjp->inst_idx;
203
+ cjp->inst_lst[*inst_idx] = (struct csonpath_instruction){.inst=inst};
204
+ *inst_idx += 1;
195
205
  }
196
206
 
197
207
  static inline void csonpath_push_inst_cpy(struct csonpath cjp[static 1],
198
- struct csonpath_instruction inst)
208
+ const struct csonpath_instruction inst,
209
+ int *inst_idx)
199
210
  {
200
- if (cjp->inst_idx + 1 > cjp->inst_size) {
201
- cjp->inst_size = cjp->inst_size << 1;
202
- cjp->inst_lst = realloc(cjp->inst_lst, cjp->inst_size);
203
- assert(cjp->inst_lst);
204
- }
205
- cjp->inst_lst[cjp->inst_idx] = inst;
206
- ++cjp->inst_idx;
211
+ cjp->inst_lst[*inst_idx] = inst;
212
+ *inst_idx += 1;
207
213
  }
208
214
 
209
215
  static void csonpath_print_instruction(struct csonpath cjp[static 1])
@@ -226,7 +232,9 @@ static int csonpath_compile(struct csonpath cjp[static 1])
226
232
  char *orig = walker;
227
233
  char *next;
228
234
  char to_check;
235
+ int inst_idx = 0;
229
236
  char *tmp; /* tmp is only here for debug */
237
+ int inst;
230
238
 
231
239
  if (cjp->compiled)
232
240
  return 0;
@@ -234,8 +242,8 @@ static int csonpath_compile(struct csonpath cjp[static 1])
234
242
  tmp = strdup(cjp->path);
235
243
  root_again:
236
244
  CSONPATH_SKIP('$', walker);
237
- csonpath_push_inst(cjp, CSONPATH_INST_ROOT);
238
- cjp->inst_lst[cjp->inst_idx - 1].next = 1;
245
+ csonpath_push_inst(cjp, CSONPATH_INST_ROOT, &inst_idx);
246
+ cjp->inst_lst[inst_idx - 1].next = 1;
239
247
  to_check = *walker;
240
248
 
241
249
  again:
@@ -244,15 +252,21 @@ again:
244
252
  {
245
253
  int end;
246
254
 
255
+ inst = 0;
247
256
  do_array:
248
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
257
+ cjp->inst_lst[inst_idx - 1].next += 1;
249
258
  ++walker;
250
259
  if (*walker == '*') {
251
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ALL);
260
+ if (inst == CSONPATH_INST_FIND_ALL) {
261
+ CSONPATH_COMPILE_ERR(tmp, walker - orig, "'%c' is invalide here\n",
262
+ *walker);
263
+ goto error;
264
+ }
265
+ csonpath_push_inst(cjp, CSONPATH_INST_GET_ALL, &inst_idx);
252
266
  if (walker[1] != ']') {
253
267
  CSONPATH_COMPILE_ERR(tmp, walker - orig, "%s", "unclose bracket\n");
254
268
  }
255
- cjp->inst_lst[cjp->inst_idx - 1].next = 2;
269
+ cjp->inst_lst[inst_idx - 1].next = 2;
256
270
  walker += 2;
257
271
  to_check = *walker;
258
272
  goto again;
@@ -263,13 +277,18 @@ again:
263
277
  struct csonpath_instruction filter_getter[CSONPATH_TMP_BUF_SIZE];
264
278
  struct csonpath_instruction *last_inst;
265
279
  int regex_idx = -1;
266
- int inst;
267
280
  int getter_end = 0;
281
+ int operand_instruction;
268
282
 
283
+ if (inst == CSONPATH_INST_FIND_ALL) {
284
+ CSONPATH_COMPILE_ERR(tmp, walker - orig, "'%c' is invalide here\n",
285
+ *walker);
286
+ goto error;
287
+ }
269
288
  inst = CSONPATH_INST_GET_OBJ;
270
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
289
+ cjp->inst_lst[inst_idx - 1].next += 1;
271
290
  ++walker;
272
- last_inst = &cjp->inst_lst[cjp->inst_idx - 1];
291
+ last_inst = &cjp->inst_lst[inst_idx - 1];
273
292
  if (*walker == '(') {
274
293
  have_parentesis = 1;
275
294
  ++walker;
@@ -280,9 +299,9 @@ again:
280
299
  } else {
281
300
  CSONPATH_SKIP('.', walker);
282
301
  }
283
- cjp->inst_lst[cjp->inst_idx - 1].next += 3;
302
+ cjp->inst_lst[inst_idx - 1].next += 3;
284
303
  for (; isblank(*walker); ++walker)
285
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
304
+ cjp->inst_lst[inst_idx - 1].next += 1;
286
305
  } else if (*walker == '[') {
287
306
  ++walker;
288
307
  last_inst->next++;
@@ -293,6 +312,7 @@ again:
293
312
  if (getter_end != '\'' && getter_end != '"') {
294
313
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
295
314
  "string require here, got '%c'", getter_end);
315
+ goto error;
296
316
  }
297
317
  last_inst->next += 1;
298
318
  ++walker;
@@ -356,35 +376,46 @@ again:
356
376
  }
357
377
  /* = and == are the same here */
358
378
  if (to_check == '=') {
359
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_EQ);
379
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_EQ, &inst_idx);
360
380
  if (next[0] == '=')
361
381
  ++next;
362
382
  else if (next[0] == '~') {
363
- cjp->inst_lst[cjp->inst_idx - 1].inst = CSONPATH_INST_FILTER_KEY_REG_EQ;
383
+ cjp->inst_lst[inst_idx - 1].inst = CSONPATH_INST_FILTER_KEY_REG_EQ;
364
384
  regex_idx = cjp->regex_cnt++;
365
385
  ++next;
366
386
  }
367
387
  } else if (to_check == '!' && next[0] == '=') {
368
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_NOT_EQ);
388
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_NOT_EQ, &inst_idx);
369
389
  ++next;
390
+ } else if (to_check == '>') {
391
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_SUPERIOR, &inst_idx);
392
+ } else if (to_check == '<') {
393
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_INFERIOR, &inst_idx);
370
394
  } else {
371
395
  CSONPATH_COMPILE_ERR(tmp, next - orig,
372
396
  "'%c': unsuported operation", to_check);
373
397
  goto error;
374
398
  }
399
+ operand_instruction = cjp->inst_lst[inst_idx - 1].inst;
375
400
  for (;isblank(*next); ++next);
376
- cjp->inst_lst[cjp->inst_idx - 1].next = 0;
377
- cjp->inst_lst[cjp->inst_idx - 1].filter_next = cjp->inst_idx + nb_getter_inst;
401
+ cjp->inst_lst[inst_idx - 1].next = 0;
402
+ cjp->inst_lst[inst_idx - 1].filter_next = inst_idx + nb_getter_inst;
378
403
  for (int i = 0; i < nb_getter_inst; ++i) {
379
- csonpath_push_inst_cpy(cjp, filter_getter[i]);
404
+ csonpath_push_inst_cpy(cjp, filter_getter[i], &inst_idx);
380
405
  }
381
- cjp->inst_lst[cjp->inst_idx - 1].next += next - walker;
406
+ cjp->inst_lst[inst_idx - 1].next += next - walker;
382
407
  walker = next;
383
408
  if (*walker == '"' || *walker == '\'' || *walker == '/') {
409
+ if (operand_instruction == CSONPATH_INST_FILTER_KEY_SUPERIOR ||
410
+ operand_instruction == CSONPATH_INST_FILTER_KEY_INFERIOR) {
411
+ CSONPATH_COMPILE_ERR(tmp, walker - orig, "string unsuported here");
412
+ goto error;
413
+ }
414
+
384
415
  char end = *walker;
385
416
  ++walker;
386
- cjp->inst_lst[cjp->inst_idx - 1].next++;
387
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_STR);
417
+ cjp->inst_lst[inst_idx - 1].next++;
418
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_STR, &inst_idx);
388
419
  for (next = walker; *next && *next != end; ++next);
389
420
  if (!*next) {
390
421
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
@@ -397,7 +428,7 @@ again:
397
428
  if (!regex_idx)
398
429
  cjp->regexs = malloc(sizeof *cjp->regexs * 255);
399
430
  int e = regcomp(&cjp->regexs[regex_idx], walker, 0);
400
- cjp->inst_lst[cjp->inst_idx - 1].regex_idx = regex_idx;
431
+ cjp->inst_lst[inst_idx - 1].regex_idx = regex_idx;
401
432
  if (e) {
402
433
  CSONPATH_COMPILE_ERR(tmp, next - orig, "regex has error\n");
403
434
  goto error;
@@ -409,29 +440,39 @@ again:
409
440
  } else {
410
441
  int n;
411
442
 
443
+ if (operand_instruction == CSONPATH_INST_FILTER_KEY_REG_EQ) {
444
+ CSONPATH_COMPILE_ERR(tmp, walker - orig, "number unsuported for regex");
445
+ goto error;
446
+ }
447
+
412
448
  for (next = walker; isdigit(*next); ++next);
413
449
  if (next == walker) {
414
450
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
415
451
  "'%c': broken filter with number",
416
452
  *walker);
417
453
  goto error;
454
+ } else if (!*next) {
455
+ CSONPATH_COMPILE_ERR(tmp, walker - orig,
456
+ "unclose filter");
457
+ goto error;
418
458
  }
459
+
419
460
  n = atoi(walker);
461
+ to_check = *next;
420
462
  if (n < 100) {
421
463
  *walker = n;
422
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_BYTE);
464
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_BYTE, &inst_idx);
423
465
  } else {
424
- MAY_ALIAS int *walk_int = (void *)walker;
425
- *walk_int = n;
426
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_INT);
427
- }
428
- if (!*next) {
429
- CSONPATH_COMPILE_ERR(tmp, walker - orig,
430
- "compilation error");
431
- goto error;
466
+ union {
467
+ int n;
468
+ char c[4];
469
+ } u = {.n=n};
470
+ walker[0] = u.c[0];
471
+ walker[1] = u.c[1];
472
+ walker[2] = u.c[2];
473
+ walker[3] = u.c[3];
474
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_INT, &inst_idx);
432
475
  }
433
- to_check = *next;
434
- *next = 0;
435
476
  }
436
477
  if (isblank(to_check)) {
437
478
  for (next++; isblank(*next); ++next);
@@ -446,13 +487,19 @@ again:
446
487
  CSONPATH_REQUIRE_ERR(']', next);
447
488
  }
448
489
  /* skip space */
449
- cjp->inst_lst[cjp->inst_idx - 1].next = next - walker + 1;
490
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
450
491
  walker = next + 1;
451
492
  to_check = *walker;
452
493
  goto again;
494
+ /* Filter out */
453
495
  } else if (*walker != '"' && *walker != '\'') {
454
496
  int num;
455
497
 
498
+ if (inst == CSONPATH_INST_FIND_ALL) {
499
+ CSONPATH_COMPILE_ERR(tmp, walker - orig, ".. require string\n");
500
+ goto error;
501
+ }
502
+
456
503
  next = walker;
457
504
  do {
458
505
  if (*next < '0' || *next > '9') {
@@ -468,7 +515,7 @@ again:
468
515
  *next = 0;
469
516
  num = atoi(walker);
470
517
  if (num < 100) {
471
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_SMALL);
518
+ csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_SMALL, &inst_idx);
472
519
  *walker = num;
473
520
  } else {
474
521
  union {
@@ -479,15 +526,17 @@ again:
479
526
  walker[1] = u.c[1];
480
527
  walker[2] = u.c[2];
481
528
  walker[3] = u.c[3];
482
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_BIG);
529
+ csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_BIG, &inst_idx);
483
530
  }
484
- cjp->inst_lst[cjp->inst_idx - 1].next = next - walker + 1;
531
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
485
532
  walker = next + 1;
486
533
  to_check = *walker;
487
534
  goto again;
488
535
  } else {
489
536
  end = *walker;
490
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
537
+ cjp->inst_lst[inst_idx - 1].next += 1;
538
+ if (inst != CSONPATH_INST_FIND_ALL)
539
+ inst = CSONPATH_INST_GET_OBJ;
491
540
 
492
541
  ++walker;
493
542
  next = walker;
@@ -503,8 +552,8 @@ again:
503
552
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
504
553
  "']' require instead of '%c'\n", *next);
505
554
 
506
- csonpath_push_inst(cjp, CSONPATH_INST_GET_OBJ);
507
- cjp->inst_lst[cjp->inst_idx - 1].next = next - walker + 1;
555
+ csonpath_push_inst(cjp, inst, &inst_idx);
556
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
508
557
 
509
558
  walker = next + 1;
510
559
  to_check = *walker;
@@ -513,20 +562,22 @@ again:
513
562
  }
514
563
  case '.':
515
564
  {
516
- int inst = CSONPATH_INST_GET_OBJ;
565
+ inst = CSONPATH_INST_GET_OBJ;
517
566
 
518
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
567
+ cjp->inst_lst[inst_idx - 1].next += 1;
519
568
  ++walker;
520
569
  if (*walker == '.') {
521
570
  inst = CSONPATH_INST_FIND_ALL;
522
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
571
+ cjp->inst_lst[inst_idx - 1].next += 1;
523
572
  ++walker;
524
573
  } else if (*walker == '*') {
525
574
  inst = CSONPATH_INST_GET_ALL;
526
575
  ++walker;
527
- if (*walker != '.' && *walker != '[' && *walker != '\0')
576
+ if (*walker != '.' && *walker != '[' && *walker != '\0') {
528
577
  CSONPATH_COMPILE_ERR(tmp, walker - orig, "unsuported characters '%c' after '*'", *walker);
529
- csonpath_push_inst(cjp, inst);
578
+ goto error;
579
+ }
580
+ csonpath_push_inst(cjp, inst, &inst_idx);
530
581
  to_check = *walker;
531
582
  goto again;
532
583
  }
@@ -539,25 +590,25 @@ again:
539
590
  to_check = *next;
540
591
  *next = 0;
541
592
 
542
- csonpath_push_inst(cjp, inst);
543
- cjp->inst_lst[cjp->inst_idx - 1].next = next - walker;
593
+ csonpath_push_inst(cjp, inst, &inst_idx);
594
+ cjp->inst_lst[inst_idx - 1].next = next - walker;
544
595
  walker = next;
545
596
  goto again;
546
597
  }
547
598
  case '|':
548
- /* cjp->inst_lst[cjp->inst_idx - 1].next += 1; */
549
- csonpath_push_inst(cjp, CSONPATH_INST_OR);
599
+ /* cjp->inst_lst[inst_idx - 1].next += 1; */
600
+ csonpath_push_inst(cjp, CSONPATH_INST_OR, &inst_idx);
550
601
  ++walker;
551
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
602
+ cjp->inst_lst[inst_idx - 1].next += 1;
552
603
  goto root_again;
553
604
  }
554
605
  if (isblank(*walker)) {
555
- cjp->inst_lst[cjp->inst_idx - 1].next += 1;
606
+ cjp->inst_lst[inst_idx - 1].next += 1;
556
607
  ++walker;
557
608
  goto again;
558
609
  }
559
610
  else if (*walker == 0) {
560
- csonpath_push_inst(cjp, CSONPATH_INST_END);
611
+ csonpath_push_inst(cjp, CSONPATH_INST_END, &inst_idx);
561
612
  cjp->compiled = 1;
562
613
  free(tmp);
563
614
  return 0;
@@ -570,6 +621,37 @@ again:
570
621
  return -1;
571
622
  }
572
623
 
624
+ static int csonpath_int_from_walker(int operand_instruction, char *walker)
625
+ {
626
+ if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_BYTE)
627
+ return *walker;
628
+ else if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_INT) {
629
+ union {int n; char c[4];} to_num =
630
+ { .c= { walker[0], walker[1], walker[2], walker[3] } };
631
+
632
+ return to_num.n;
633
+ }
634
+ return -1;
635
+ }
636
+
637
+ static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char *owalker)
638
+ {
639
+ switch (operand_instruction) {
640
+ case CSONPATH_INST_FILTER_OPERAND_STR:
641
+ return CSONPATH_EQUAL_STR(el2, owalker);
642
+ case CSONPATH_INST_FILTER_OPERAND_BYTE:
643
+ return CSONPATH_EQUAL_NUM(el2, *owalker);
644
+ case CSONPATH_INST_FILTER_OPERAND_INT:
645
+ {
646
+ union {int n; char c[4];} to_num =
647
+ { .c= { owalker[0], owalker[1], owalker[2], owalker[3] } };
648
+
649
+ return CSONPATH_EQUAL_NUM(el2, to_num.n);
650
+ }
651
+ }
652
+ return 0;
653
+ }
654
+
573
655
  /* helper use multiple times */
574
656
  #define CSONPATH_DO_GET_NOTFOUND_UPDATER(this_idx) \
575
657
  do { \
@@ -163,12 +163,15 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
163
163
  case CSONPATH_INST_FILTER_KEY_EQ:
164
164
  case CSONPATH_INST_FILTER_KEY_REG_EQ:
165
165
  case CSONPATH_INST_FILTER_KEY_NOT_EQ:
166
+ case CSONPATH_INST_FILTER_KEY_SUPERIOR:
167
+ case CSONPATH_INST_FILTER_KEY_INFERIOR:
166
168
  {
167
169
  CSONPATH_JSON el;
168
170
  int operation = cjp->inst_lst[idx].inst;
169
171
  walker += cjp->inst_lst[idx].next;
170
172
  char *owalker;
171
173
  int filter_next = cjp->inst_lst[idx].filter_next;
174
+ int operand_instruction = -1;
172
175
  int in_idx = idx + 1;
173
176
 
174
177
  CSONPATH_DO_FILTER_PRE_LOOP;
@@ -189,18 +192,31 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
189
192
  }
190
193
  owalker += cjp->inst_lst[idx].next;
191
194
  }
192
-
193
- if (cjp->inst_lst[idx].inst != CSONPATH_INST_FILTER_OPERAND_STR)
194
- CSONPATH_GETTER_ERR("unsuported instruction '%s' only FILTER_OPERAND_STR is supported here", csonpath_instuction_str[(int)cjp->inst_lst[idx].inst]);
195
+
196
+ if (operand_instruction < 0) {
197
+ operand_instruction = cjp->inst_lst[idx].inst;
198
+ }
195
199
 
196
200
  if (el2 != CSONPATH_NULL) {
197
201
  _Bool match = 0;
198
202
  switch (operation) {
199
203
  case CSONPATH_INST_FILTER_KEY_NOT_EQ:
200
- match = !CSONPATH_EQUAL_STR(el2, owalker);
204
+ match = !csonpath_do_match(operand_instruction, el2, owalker);
201
205
  break;
202
206
  case CSONPATH_INST_FILTER_KEY_EQ:
203
- match = CSONPATH_EQUAL_STR(el2, owalker);
207
+ match = csonpath_do_match(operand_instruction, el2, owalker);
208
+ break;
209
+ case CSONPATH_INST_FILTER_KEY_SUPERIOR:
210
+ if (!CSONPATH_IS_NUM(el2))
211
+ break;
212
+ match = csonpath_int_from_walker(operand_instruction, owalker) <
213
+ CSONPATH_GET_NUM(el2);
214
+ break;
215
+ case CSONPATH_INST_FILTER_KEY_INFERIOR:
216
+ if (!CSONPATH_IS_NUM(el2))
217
+ break;
218
+ match = csonpath_int_from_walker(operand_instruction, owalker) >
219
+ CSONPATH_GET_NUM(el2);
204
220
  break;
205
221
  case CSONPATH_INST_FILTER_KEY_REG_EQ:
206
222
  #ifdef CSONPATH_NO_REGEX
@@ -299,7 +315,10 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
299
315
  break;
300
316
  }
301
317
  default:
302
- CSONPATH_GETTER_ERR("unimplemented %d at idx %d\n", cjp->inst_lst[idx].inst, idx);
318
+ CSONPATH_GETTER_ERR("unimplemented %d (%s) at idx %d\n", cjp->inst_lst[idx].inst,
319
+ cjp->inst_lst[idx].inst <= CSONPATH_INST_BROKEN ?
320
+ csonpath_instuction_str[cjp->inst_lst[idx].inst] : "(unknow)",
321
+ idx);
303
322
  }
304
323
  next_inst:
305
324
  ++idx;
@@ -20,9 +20,23 @@
20
20
 
21
21
  #define CSONPATH_IS_STR(o) PyUnicode_Check(o)
22
22
 
23
+ #define CSONPATH_IS_NUM(o) PyLong_Check(o)
24
+
23
25
  #define CSONPATH_GET_STR(obj) \
24
26
  PyUnicode_AsUTF8(obj)
25
27
 
28
+ #define CSONPATH_GET_NUM(obj) \
29
+ PyLong_AsLong(obj)
30
+
31
+ #define CSONPATH_EQUAL_NUM(obj, to_cmp) \
32
+ ({ \
33
+ _Bool r = 0; \
34
+ if (PyLong_Check(obj)) { \
35
+ r = PyLong_AsLong(obj) == to_cmp; \
36
+ } \
37
+ r; \
38
+ })
39
+
26
40
  #define CSONPATH_EQUAL_STR(obj, to_cmp) ({ \
27
41
  _Bool r = 0; \
28
42
  if (PyUnicode_Check(obj)) { \
@@ -78,7 +92,7 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
78
92
  PyErr_Format(PyExc_ValueError, "Unable to follow path: List expected");
79
93
  return -1;
80
94
  }
81
- size_t s = PyList_Size(array);
95
+ Py_ssize_t s = PyList_Size(array);
82
96
  if (at >= s) {
83
97
  for (;s < at; ++s)
84
98
  PyList_Insert(array, s, Py_None);
@@ -86,7 +100,8 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
86
100
  PyList_Insert(array, at, el);
87
101
  } else {
88
102
  Py_INCREF(el);
89
- PyList_SetItem(array, at, el);
103
+ if (PyList_SetItem(array, at, el) < 0)
104
+ Py_DECREF(el);
90
105
  }
91
106
  return 1;
92
107
  }
@@ -189,14 +204,6 @@ static PyObject *find_all(PyCsonPathObject *self, PyObject* args)
189
204
  if (!PyArg_ParseTuple(args, "O", &json))
190
205
  BAD_ARG();
191
206
  PyObject *ret = csonpath_find_all(self->cp, json);
192
- if (ret != Py_None) {
193
- PyObject *key_;
194
- Py_ssize_t pos_ = 0;
195
- PyObject *el;
196
- while (PyDict_Next(ret, &pos_, &key_, &el)) {
197
- Py_INCREF(el);
198
- }
199
- }
200
207
  return ret;
201
208
  }
202
209
 
@@ -207,7 +214,6 @@ static PyObject *find_first(PyCsonPathObject *self, PyObject* args)
207
214
  if (!PyArg_ParseTuple(args, "O", &json))
208
215
  BAD_ARG();
209
216
  PyObject *ret = csonpath_find_first(self->cp, json);
210
- Py_INCREF(ret);
211
217
  return ret;
212
218
  }
213
219
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "csonpath"
7
- version = "0.4.0"
7
+ version = "0.6.0"
8
8
  readme = "README.md"
9
9
 
10
10
  [tool.setuptools]
@@ -22,7 +22,7 @@ dev = [
22
22
  testpaths = ["tests/python"]
23
23
 
24
24
  [tool.bumpversion]
25
- current_version = "0.4.0"
25
+ current_version = "0.6.0"
26
26
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
27
27
  serialize = ["{major}.{minor}.{patch}"]
28
28
  search = "{current_version}"
File without changes
File without changes
File without changes