csonpath 0.8.0__tar.gz → 0.10.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.8.0
3
+ Version: 0.10.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -40,9 +40,10 @@ Dynamic: license-file
40
40
  - support `..`: `"$..non`
41
41
  - support `[*]`: `"$.array[*].obj[*].field"`
42
42
  - support filters:
43
- - with `>` or `<`: `"$.obj[?.field > 123]"`
44
- - with `=` or '!=': `"$.obj[?.field != "123"]"`
43
+ - with `>` or `<`: `"$.obj[?field > 123]"`
44
+ - with `=` or '!=': `"$.obj[?field != "123"]"`
45
45
  - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
46
+ - with `&`: `"$.obj[?field != "123" & second = 1]"`
46
47
  - support `|`: `"$.obj | $.otherobj"`
47
48
  ### Functions
48
49
  - **Find First**: Retrieve the first value matching a path.
@@ -31,9 +31,10 @@
31
31
  - support `..`: `"$..non`
32
32
  - support `[*]`: `"$.array[*].obj[*].field"`
33
33
  - support filters:
34
- - with `>` or `<`: `"$.obj[?.field > 123]"`
35
- - with `=` or '!=': `"$.obj[?.field != "123"]"`
34
+ - with `>` or `<`: `"$.obj[?field > 123]"`
35
+ - with `=` or '!=': `"$.obj[?field != "123"]"`
36
36
  - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
37
+ - with `&`: `"$.obj[?field != "123" & second = 1]"`
37
38
  - support `|`: `"$.obj | $.otherobj"`
38
39
  ### Functions
39
40
  - **Find First**: Retrieve the first value matching a path.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.8.0
3
+ Version: 0.10.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -40,9 +40,10 @@ Dynamic: license-file
40
40
  - support `..`: `"$..non`
41
41
  - support `[*]`: `"$.array[*].obj[*].field"`
42
42
  - support filters:
43
- - with `>` or `<`: `"$.obj[?.field > 123]"`
44
- - with `=` or '!=': `"$.obj[?.field != "123"]"`
43
+ - with `>` or `<`: `"$.obj[?field > 123]"`
44
+ - with `=` or '!=': `"$.obj[?field != "123"]"`
45
45
  - with regex, using POSIX regcom: `"$.obj[?.field ~= "123"]"`
46
+ - with `&`: `"$.obj[?field != "123" & second = 1]"`
46
47
  - support `|`: `"$.obj | $.otherobj"`
47
48
  ### Functions
48
49
  - **Find First**: Retrieve the first value matching a path.
@@ -33,6 +33,14 @@
33
33
  #define CSONPATH_DECREF(obj)
34
34
  #endif
35
35
 
36
+ #ifndef CSONPATH_FORMAT_EXCEPTION
37
+ #define CSONPATH_FORMAT_EXCEPTION(args...) fprintf(stderr, args)
38
+ #endif
39
+
40
+ #ifndef CSONPATH_EXCEPTION
41
+ #define CSONPATH_EXCEPTION(args...) CSONPATH_GETTER_ERR(args)
42
+ #endif
43
+
36
44
  enum csonpath_instuction_raw {
37
45
  CSONPATH_INST_ROOT,
38
46
  CSONPATH_INST_GET_OBJ,
@@ -46,8 +54,10 @@ enum csonpath_instuction_raw {
46
54
  CSONPATH_INST_FILTER_OPERAND_STR,
47
55
  CSONPATH_INST_FILTER_OPERAND_BYTE, /* store the same way it's in ARRAY_SMALL */
48
56
  CSONPATH_INST_FILTER_OPERAND_INT, /* store the same way it's in ARRAY_BIG */
57
+ CSONPATH_INST_FILTER_AND,
49
58
  CSONPATH_INST_GET_ALL,
50
59
  CSONPATH_INST_FIND_ALL,
60
+ CSONPATH_INST_RANGE,
51
61
  CSONPATH_INST_OR,
52
62
  CSONPATH_INST_END,
53
63
  CSONPATH_INST_BROKEN
@@ -68,8 +78,10 @@ CSONPATH_UNUSED static const char *csonpath_instuction_str[] = {
68
78
  "FILTER_OPERAND_STR",
69
79
  "FILTER_OPERAND_BYTE",
70
80
  "FILTER_OPERAND_INT",
81
+ "FILTER_AND",
71
82
  "GET_ALL",
72
83
  "FIND_ALL",
84
+ "RANGE",
73
85
  "OR",
74
86
  "END",
75
87
  "BROKEN"
@@ -230,6 +242,43 @@ static inline _Bool csonpath_is_dot_operand(int c)
230
242
  return isalnum(c) || c == '_' || c == '-';
231
243
  }
232
244
 
245
+
246
+ static int csonpath_fill_walker_with_int(char *walker, int num, int first_ret)
247
+ {
248
+ if (num < 100) {
249
+ *walker = num;
250
+ return first_ret;
251
+ }
252
+ union {
253
+ int n;
254
+ char c[4];
255
+ } u = {.n=num};
256
+ walker[0] = u.c[0];
257
+ walker[1] = u.c[1];
258
+ walker[2] = u.c[2];
259
+ walker[3] = u.c[3];
260
+ return first_ret + 1;
261
+ }
262
+
263
+ static int csonpath_int_from_walker(int operand_instruction, char *walker)
264
+ {
265
+ switch(operand_instruction) {
266
+ case CSONPATH_INST_FILTER_OPERAND_BYTE:
267
+ case CSONPATH_INST_GET_ARRAY_SMALL:
268
+ return *walker;
269
+ case CSONPATH_INST_GET_ARRAY_BIG:
270
+ case CSONPATH_INST_FILTER_OPERAND_INT:
271
+ {
272
+ union {int n; char c[4];} to_num =
273
+ { .c= { walker[0], walker[1], walker[2], walker[3] } };
274
+ return to_num.n;
275
+ }
276
+ default:
277
+ break;
278
+ }
279
+ return -1;
280
+ }
281
+
233
282
  static int csonpath_compile(struct csonpath cjp[static 1])
234
283
  {
235
284
  char *walker = cjp->path;
@@ -244,13 +293,13 @@ static int csonpath_compile(struct csonpath cjp[static 1])
244
293
  return 0;
245
294
 
246
295
  tmp = strdup(cjp->path);
247
- root_again:
296
+ root_again:
248
297
  CSONPATH_SKIP('$', walker);
249
298
  csonpath_push_inst(cjp, CSONPATH_INST_ROOT, &inst_idx);
250
299
  cjp->inst_lst[inst_idx - 1].next = 1;
251
300
  to_check = *walker;
252
301
 
253
- again:
302
+ again:
254
303
  switch (to_check) {
255
304
  case '[':
256
305
  {
@@ -289,12 +338,18 @@ again:
289
338
  *walker);
290
339
  goto error;
291
340
  }
341
+ filter_again_root:
292
342
  inst = CSONPATH_INST_GET_OBJ;
293
343
  cjp->inst_lst[inst_idx - 1].next += 1;
294
344
  ++walker;
345
+
346
+ /* skipp blank */
347
+ for (; isblank(*walker); ++walker)
348
+ cjp->inst_lst[inst_idx - 1].next += 1;
349
+
295
350
  last_inst = &cjp->inst_lst[inst_idx - 1];
296
351
  if (*walker == '(') {
297
- have_parentesis = 1;
352
+ ++have_parentesis;
298
353
  ++walker;
299
354
  CSONPATH_SKIP('@', walker);
300
355
  if (*walker == '[') {
@@ -356,7 +411,7 @@ again:
356
411
  filter_getter[nb_getter_inst-1].next += 1;
357
412
  ++next;
358
413
  to_check = *next;
359
- have_parentesis = 0;
414
+ have_parentesis--;
360
415
  }
361
416
 
362
417
  walker = next;
@@ -463,34 +518,37 @@ again:
463
518
 
464
519
  n = atoi(walker);
465
520
  to_check = *next;
466
- if (n < 100) {
467
- *walker = n;
468
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_BYTE, &inst_idx);
469
- } else {
470
- union {
471
- int n;
472
- char c[4];
473
- } u = {.n=n};
474
- walker[0] = u.c[0];
475
- walker[1] = u.c[1];
476
- walker[2] = u.c[2];
477
- walker[3] = u.c[3];
478
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_INT, &inst_idx);
479
- }
521
+ csonpath_push_inst(cjp, csonpath_fill_walker_with_int(
522
+ walker, n, CSONPATH_INST_FILTER_OPERAND_BYTE), &inst_idx);
480
523
  }
524
+
525
+ /* skip space */
481
526
  if (isblank(to_check)) {
482
527
  for (next++; isblank(*next); ++next);
483
528
  to_check = *next;
484
529
  }
485
530
 
486
- if (have_parentesis) {
531
+ if (to_check == '&') {
532
+ if (next[1] == '&') {
533
+ ++next;
534
+ }
535
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
536
+ walker = next + 1;
537
+ to_check = *walker;
538
+ csonpath_push_inst(cjp, CSONPATH_INST_FILTER_AND, &inst_idx);
539
+ nb_getter_inst = 0;
540
+ goto filter_again_root;
541
+ }
542
+
543
+ while (have_parentesis) {
487
544
  CSONPATH_SKIP(')', next);
488
545
  to_check = *next;
546
+ --have_parentesis;
489
547
  }
548
+
490
549
  if (to_check != ']') {
491
550
  CSONPATH_REQUIRE_ERR(']', next);
492
551
  }
493
- /* skip space */
494
552
  cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
495
553
  walker = next + 1;
496
554
  to_check = *walker;
@@ -506,11 +564,23 @@ again:
506
564
 
507
565
  next = walker;
508
566
  do {
509
- if (*next < '0' || *next > '9') {
510
- CSONPATH_COMPILE_ERR(tmp, walker - orig,
511
- "unexpected '%c', sting, filter or number require\n", *next);
512
- }
513
- next++;
567
+ if (*next == ':') {
568
+ csonpath_push_inst(cjp, CSONPATH_INST_RANGE, &inst_idx);
569
+ num = atoi(walker);
570
+ csonpath_push_inst(
571
+ cjp, csonpath_fill_walker_with_int(
572
+ walker, num, CSONPATH_INST_GET_ARRAY_SMALL),
573
+ &inst_idx);
574
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
575
+ walker = next + 1;
576
+ ++next;
577
+ continue;
578
+ }
579
+ if (*next < '0' || *next > '9') {
580
+ CSONPATH_COMPILE_ERR(tmp, walker - orig,
581
+ "unexpected '%c', sting, filter or number require\n", *next);
582
+ }
583
+ next++;
514
584
  } while (*next && *next != ']');
515
585
  if (!*next) {
516
586
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
@@ -518,20 +588,9 @@ again:
518
588
  }
519
589
  *next = 0;
520
590
  num = atoi(walker);
521
- if (num < 100) {
522
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_SMALL, &inst_idx);
523
- *walker = num;
524
- } else {
525
- union {
526
- int n;
527
- char c[4];
528
- } u = {.n=num};
529
- walker[0] = u.c[0];
530
- walker[1] = u.c[1];
531
- walker[2] = u.c[2];
532
- walker[3] = u.c[3];
533
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_BIG, &inst_idx);
534
- }
591
+ csonpath_push_inst(cjp, csonpath_fill_walker_with_int(
592
+ walker, num, CSONPATH_INST_GET_ARRAY_SMALL),
593
+ &inst_idx);
535
594
  cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
536
595
  walker = next + 1;
537
596
  to_check = *walker;
@@ -625,19 +684,6 @@ again:
625
684
  return -1;
626
685
  }
627
686
 
628
- static int csonpath_int_from_walker(int operand_instruction, char *walker)
629
- {
630
- if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_BYTE)
631
- return *walker;
632
- else if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_INT) {
633
- union {int n; char c[4];} to_num =
634
- { .c= { walker[0], walker[1], walker[2], walker[3] } };
635
-
636
- return to_num.n;
637
- }
638
- return -1;
639
- }
640
-
641
687
  static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char *owalker)
642
688
  {
643
689
  switch (operand_instruction) {
@@ -656,6 +702,79 @@ static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char
656
702
  return 0;
657
703
  }
658
704
 
705
+ static CSONPATH_JSON cosnpath_crawl_filter_el(struct csonpath cjp[static 1],
706
+ int *idx, char **owalker,
707
+ CSONPATH_JSON el2,
708
+ int filter_next)
709
+ {
710
+
711
+ for (; *idx < filter_next; ++(*idx)) {
712
+ switch (cjp->inst_lst[*idx].inst) {
713
+ case CSONPATH_INST_GET_OBJ:
714
+ el2 = CSONPATH_GET(el2, *owalker);
715
+ break;
716
+ default:
717
+ CSONPATH_FORMAT_EXCEPTION("unsuported %s inst",
718
+ csonpath_instuction_str[cjp->inst_lst[*idx].inst]);
719
+ return NULL;
720
+ }
721
+ (*owalker) += cjp->inst_lst[*idx].next;
722
+ }
723
+ return el2;
724
+ }
725
+
726
+
727
+ static _Bool csonpath_make_match(struct csonpath cjp[static 1],
728
+ struct csonpath_instruction inst[static 1],
729
+ CSONPATH_JSON el2, char *owalker, int operation)
730
+ {
731
+ int operand_instruction = inst->inst;
732
+
733
+ if (el2 == CSONPATH_NULL)
734
+ return 0;
735
+ _Bool match = 0;
736
+ switch (operation) {
737
+ case CSONPATH_INST_FILTER_KEY_NOT_EQ:
738
+ match = !csonpath_do_match(operand_instruction, el2, owalker);
739
+ break;
740
+ case CSONPATH_INST_FILTER_KEY_EQ:
741
+ match = csonpath_do_match(operand_instruction, el2, owalker);
742
+ break;
743
+ case CSONPATH_INST_FILTER_KEY_SUPERIOR:
744
+ if (!CSONPATH_IS_NUM(el2))
745
+ break;
746
+ match = csonpath_int_from_walker(operand_instruction, owalker) <
747
+ CSONPATH_GET_NUM(el2);
748
+ break;
749
+ case CSONPATH_INST_FILTER_KEY_INFERIOR:
750
+ if (!CSONPATH_IS_NUM(el2))
751
+ break;
752
+ match = csonpath_int_from_walker(operand_instruction, owalker) >
753
+ CSONPATH_GET_NUM(el2);
754
+ break;
755
+ case CSONPATH_INST_FILTER_KEY_REG_EQ:
756
+ #ifdef CSONPATH_NO_REGEX
757
+ CSONPATH_GETTER_ERR("regex deactivate\n");
758
+ return CSONPATH_NONE_FOUND_RET;
759
+ #else
760
+ if (CSONPATH_IS_STR(el2)) {
761
+ int regex_idx = inst->regex_idx;
762
+ regex_t *compiled = &cjp->regexs[regex_idx];
763
+ int match_len = regexec(compiled, CSONPATH_GET_STR(el2),
764
+ 0, NULL, 0);
765
+ match = match_len == 0;
766
+ }
767
+ break;
768
+ #endif
769
+ }
770
+ return match;
771
+ }
772
+
773
+ static _Bool csonpath_is_endish_inst(int instruction)
774
+ {
775
+ return instruction == CSONPATH_INST_END || instruction == CSONPATH_INST_OR;
776
+ }
777
+
659
778
  /* helper use multiple times */
660
779
  #define CSONPATH_DO_GET_NOTFOUND_UPDATER(this_idx) \
661
780
  do { \
@@ -674,7 +793,8 @@ static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char
674
793
  goto next_inst; \
675
794
  } while (0)
676
795
 
677
- #define CSONPATH_GOTO_ON_RELOOP(where) \
796
+
797
+ #define CSONPATH_GOTO_ON_RELOOP(where) \
678
798
  nb_res += tret; if (need_reloop_in) goto where;
679
799
 
680
800
  #define CSONPATH_PREPARE_RELOOP(label) \
@@ -776,15 +896,26 @@ need_reloop_in = 0;
776
896
  #define CSONPATH_DO_FILTER_FIND nb_res += tret;
777
897
 
778
898
  #define CSONPATH_DO_FIND_ALL ({ \
779
- if (tret < 0) return -1; \
780
- nb_res += tret; \
781
- if (need_reloop_in){ goto again; }; \
782
- })
899
+ if (tret < 0) return -1; \
900
+ nb_res += tret; \
901
+ if (need_reloop_in){ goto again; }; \
902
+ })
903
+
904
+ #define CSONPATH_DO_RANGE ({ \
905
+ if (tret < 0) return -1; \
906
+ nb_res += tret; \
907
+ --end; \
908
+ if (need_reloop_in){ goto range_again; }; \
909
+ })
783
910
 
784
911
  #define CSONPATH_DO_EXTRA_DECLATION , struct csonpath_child_info child_info, int *need_reloop
785
912
 
786
913
  #define CSONPATH_DO_EXTRA_ARGS_IN , (struct csonpath_child_info) {.type = CSONPATH_NONE}, NULL
787
914
 
915
+ #define CSONPATH_DO_RANGE_PRE_LOOP \
916
+ int need_reloop_in; \
917
+ range_again:
918
+
788
919
  #define CSONPATH_DO_FILTER_PRE_LOOP \
789
920
  int need_reloop_in;
790
921
 
@@ -793,11 +924,11 @@ need_reloop_in = 0;
793
924
  again:
794
925
 
795
926
  #define CSONPATH_DO_FILTER_LOOP_PRE_SET \
796
- csonpath_child_info_set(&child_info, tmp, (intptr_t)key_idx);
927
+ csonpath_child_info_set(&child_info, tmp, foreach_idx);
797
928
 
798
929
  #define CSONPATH_DO_FOREACH_PRE_SET \
799
- need_reloop_in = 0; \
800
- csonpath_child_info_set(&child_info, tmp, (intptr_t)key_idx);
930
+ need_reloop_in = 0; \
931
+ csonpath_child_info_set(&child_info, tmp, (intptr_t)key_idx);
801
932
 
802
933
  #define CSONPATH_DO_EXTRA_ARGS_NEESTED , child_info, &need_reloop_in
803
934
 
@@ -846,6 +977,41 @@ again:
846
977
 
847
978
  #define CSONPATH_DO_FIND_ALL_OUT return nb_res;
848
979
 
980
+ static int csonpath_sync_root_array(CSONPATH_JSON parent, CSONPATH_JSON to_update)
981
+ {
982
+ CSONPATH_JSON child;
983
+ size_t idx;
984
+ (void) idx;
985
+
986
+ CSONPATH_ARRAY_CLEAR(parent);
987
+ CSONPATH_FOREACH_ARRAY(to_update, child, idx) {
988
+ CSONPATH_APPEND_AT(parent, idx, child);
989
+ }
990
+ return 1;
991
+ }
992
+
993
+ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
994
+ {
995
+ CSONPATH_JSON child;
996
+ const char *key;
997
+
998
+ CSONPATH_OBJ_CLEAR(parent);
999
+ CSONPATH_FOREACH_OBJ(to_update, child, key) {
1000
+ CSONPATH_APPEND_AT(parent, key, child);
1001
+ }
1002
+ return 1;
1003
+ }
1004
+
1005
+ #define CSONPATH_PRE_GET_ROOT \
1006
+ int to_check = cjp->inst_lst[idx + 1].inst; \
1007
+ if (to_check == CSONPATH_INST_END || to_check == CSONPATH_INST_OR) { \
1008
+ if (CSONPATH_IS_OBJ(origin) && CSONPATH_IS_OBJ(to_update)) \
1009
+ return csonpath_sync_root_obj(origin, to_update); \
1010
+ else if (CSONPATH_IS_ARRAY(origin) && CSONPATH_IS_ARRAY(to_update)) \
1011
+ return csonpath_sync_root_array(origin, to_update); \
1012
+ else \
1013
+ CSONPATH_EXCEPTION("can't upate root ($)\n"); \
1014
+ }
849
1015
 
850
1016
  #define CSONPATH_PRE_GET(this_idx) \
851
1017
  int check_at = idx + 1; \
@@ -906,17 +1072,16 @@ again:
906
1072
  #define CSONPATH_DO_RETURN \
907
1073
  if (tmp == value) { \
908
1074
  *need_reloop = 1; \
909
- CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); \
910
- return 1; \
911
1075
  } \
912
- return 0;
1076
+ CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); \
1077
+ return 1;
913
1078
 
914
1079
  #define CSONPATH_DO_EXTRA_ARGS_FIND_ALL , callback, udata, NULL, need_reloop
915
1080
  #define CSONPATH_DO_EXTRA_ARGS_NEESTED , callback, udata, \
916
1081
  csonpath_child_info_set(&(struct csonpath_child_info ){}, tmp, (intptr_t)key_idx), \
917
1082
  &need_reloop_in
918
1083
  #define CSONPATH_DO_EXTRA_ARGS , CSONPATH_CALLBACK callback, CSONPATH_CALLBACK_DATA udata
919
- #define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, NULL, NULL
1084
+ #define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, &(struct csonpath_child_info ){}, NULL
920
1085
  #define CSONPATH_DO_EXTRA_DECLATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
921
1086
  #define CSONPATH_DO_FIND_ALL nb_res += tret;
922
1087
  #define CSONPATH_DO_FILTER_FIND CSONPATH_GOTO_ON_RELOOP(filter_again)
@@ -927,21 +1092,16 @@ again:
927
1092
 
928
1093
  #define CSONPATH_DO_FIND_ALL_OUT return nb_res;
929
1094
 
1095
+ #define CSONPATH_PRE_GET_ROOT \
1096
+ int to_check = cjp->inst_lst[idx + 1].inst; \
1097
+ if (to_check == CSONPATH_INST_END || to_check == CSONPATH_INST_OR) { \
1098
+ CSONPATH_GETTER_ERR("can't upate root ($)\n"); \
1099
+ return CSONPATH_NONE_FOUND_RET; \
1100
+ }
930
1101
 
931
1102
  #define CSONPATH_PRE_GET(this_idx) \
932
- int check_at = idx + 1; \
933
- int to_check; \
934
- do { \
935
- to_check = cjp->inst_lst[check_at].inst; \
936
- ++check_at; \
937
- } while (to_check == CSONPATH_INST_GET_ALL || to_check == CSONPATH_INST_FIND_ALL); \
938
- if (to_check == CSONPATH_INST_END || to_check == CSONPATH_INST_OR) { \
939
- CSONPATH_CALL_CALLBACK( \
940
- callback, ctx, \
941
- csonpath_child_info_set(&(struct csonpath_child_info ){}, \
942
- ctx, (intptr_t)this_idx), tmp, udata); \
943
- return 1; \
944
- }
1103
+ int to_check = cjp->inst_lst[idx].inst; \
1104
+ csonpath_child_info_set(child_info, ctx, (intptr_t)this_idx)
945
1105
 
946
1106
 
947
1107
  #define CSONPATH_DO_GET_NOTFOUND(this_idx) \
@@ -17,6 +17,10 @@
17
17
  #define CSONPATH_PRE_GET(this_idx)
18
18
  #endif
19
19
 
20
+ #ifndef CSONPATH_PRE_GET_ROOT
21
+ #define CSONPATH_PRE_GET_ROOT
22
+ #endif
23
+
20
24
  #ifndef CSONPATH_DO_DECLARATION
21
25
  #define CSONPATH_DO_DECLARATION
22
26
  #endif
@@ -89,6 +93,18 @@
89
93
  #define CSONPATH_DO_FILTER_LOOP_PRE_SET
90
94
  #endif
91
95
 
96
+ #ifndef CSONPATH_DO_RANGE
97
+ #define CSONPATH_DO_RANGE CSONPATH_DO_FIND_ALL
98
+ #endif
99
+
100
+ #ifndef CSONPATH_DO_RANGE
101
+ #define CSONPATH_DO_RANGE CSONPATH_DO_FIND_ALL
102
+ #endif
103
+
104
+ #ifndef CSONPATH_DO_RANGE_PRE_LOOP
105
+ #define CSONPATH_DO_RANGE_PRE_LOOP CSONPATH_DO_FIND_ALL_PRE_LOOP
106
+ #endif
107
+
92
108
  #ifndef CAT
93
109
  # define CATCAT(a, b, c) a ## b ## c
94
110
  # define CAT(a, b) a ## b
@@ -104,6 +120,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
104
120
  int idx,
105
121
  char *walker CSONPATH_DO_EXTRA_DECLATION);
106
122
 
123
+
107
124
  #define csonpath_do_dotdot__(name) CATCAT(csonpath_, name, _dotdot)
108
125
  #define csonpath_do_dotdot csonpath_do_dotdot__(CSONPATH_DO_FUNC_NAME)
109
126
 
@@ -155,11 +172,14 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
155
172
  cjp->inst_lst[idx].inst != CSONPATH_INST_OR) {
156
173
  switch (cjp->inst_lst[idx].inst) {
157
174
  case CSONPATH_INST_ROOT:
175
+ {
176
+ CSONPATH_PRE_GET_ROOT
158
177
  value = origin;
159
178
  tmp = value;
160
179
  ctx = CSONPATH_NULL;
161
180
  walker += cjp->inst_lst[idx].next;
162
- break;
181
+ }
182
+ break;
163
183
  case CSONPATH_INST_FILTER_KEY_EQ:
164
184
  case CSONPATH_INST_FILTER_KEY_REG_EQ:
165
185
  case CSONPATH_INST_FILTER_KEY_NOT_EQ:
@@ -167,83 +187,54 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
167
187
  case CSONPATH_INST_FILTER_KEY_INFERIOR:
168
188
  {
169
189
  CSONPATH_JSON el;
170
- int operation = cjp->inst_lst[idx].inst;
190
+ int operation_in = cjp->inst_lst[idx].inst, operation = cjp->inst_lst[idx].inst;
171
191
  walker += cjp->inst_lst[idx].next;
172
192
  char *owalker;
173
- int filter_next = cjp->inst_lst[idx].filter_next;
174
- int operand_instruction = -1;
175
- int in_idx = idx + 1;
193
+ int filter_next_in = cjp->inst_lst[idx].filter_next, filter_next = cjp->inst_lst[idx].filter_next;
194
+ int walker_idx = idx + 1, in_idx = idx + 1;
195
+ int foreach_idx;
176
196
 
197
+ (void) foreach_idx;
177
198
  CSONPATH_DO_FILTER_PRE_LOOP;
178
- CSONPATH_FOREACH(tmp, el, {
179
- if (CSONPATH_IS_OBJ(el)) {
180
- CSONPATH_JSON el2 = el;
181
-
182
- owalker = walker;
183
- idx = in_idx;
184
- CSONPATH_DO_FILTER_LOOP_PRE_SET;
185
- for (; idx < filter_next; ++idx) {
186
- switch (cjp->inst_lst[idx].inst) {
187
- case CSONPATH_INST_GET_OBJ:
188
- el2 = CSONPATH_GET(el2, owalker);
189
- break;
190
- default:
191
- CSONPATH_GETTER_ERR("unsuported");
192
- }
193
- owalker += cjp->inst_lst[idx].next;
194
- }
195
-
196
- if (operand_instruction < 0) {
197
- operand_instruction = cjp->inst_lst[idx].inst;
198
- }
199
-
200
- if (el2 != CSONPATH_NULL) {
201
- _Bool match = 0;
202
- switch (operation) {
203
- case CSONPATH_INST_FILTER_KEY_NOT_EQ:
204
- match = !csonpath_do_match(operand_instruction, el2, owalker);
205
- break;
206
- case CSONPATH_INST_FILTER_KEY_EQ:
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);
220
- break;
221
- case CSONPATH_INST_FILTER_KEY_REG_EQ:
222
- #ifdef CSONPATH_NO_REGEX
223
- CSONPATH_GETTER_ERR("regex deactivate\n");
224
- return CSONPATH_NONE_FOUND_RET;
225
- #else
226
- if (CSONPATH_IS_STR(el2)) {
227
- int regex_idx = cjp->inst_lst[idx].regex_idx;
228
- regex_t *compiled = &cjp->regexs[regex_idx];
229
- int match_len = regexec(compiled, CSONPATH_GET_STR(el2),
230
- 0, NULL, 0);
231
- match = match_len == 0;
232
- }
233
- break;
234
- #endif
235
- }
236
- if (match) {
237
- CSONPATH_DO_RET_TYPE tret =
238
- csonpath_do_internal(cjp, origin, el, tmp, idx + 1,
239
- owalker + cjp->inst_lst[idx].next
240
- CSONPATH_DO_EXTRA_ARGS_NEESTED);
241
-
242
- CSONPATH_DO_FILTER_FIND;
243
- }
199
+ CSONPATH_FOREACH_ARRAY(tmp, el, foreach_idx)
200
+ {
201
+ intptr_t key_idx = foreach_idx;
202
+ (void)key_idx;
203
+ owalker = walker;
204
+ match_and_or_or:
205
+ if (CSONPATH_IS_OBJ(el)) {
206
+ CSONPATH_JSON el2 = el;
207
+
208
+ idx = walker_idx;
209
+ CSONPATH_DO_FILTER_LOOP_PRE_SET;
210
+ el2 = cosnpath_crawl_filter_el(cjp, &idx, &owalker, el2, filter_next);
211
+
212
+ if (csonpath_make_match(cjp, &cjp->inst_lst[idx], el2, owalker,
213
+ operation)) {
214
+ if (cjp->inst_lst[idx + 1].inst == CSONPATH_INST_FILTER_AND) {
215
+ ++idx; /* skip next */
216
+ if (csonpath_is_endish_inst(cjp->inst_lst[idx + 1].inst) ||
217
+ csonpath_is_endish_inst(cjp->inst_lst[idx + 2].inst))
218
+ goto fail_match;
219
+ operation = cjp->inst_lst[idx +1].inst;
220
+ filter_next = cjp->inst_lst[idx +1].filter_next;
221
+ owalker += cjp->inst_lst[idx].next + cjp->inst_lst[idx-1].next;
222
+ walker_idx = idx + 2;
223
+ goto match_and_or_or;
244
224
  }
225
+ CSONPATH_DO_RET_TYPE tret =
226
+ csonpath_do_internal(cjp, origin, el, tmp, idx + 1,
227
+ owalker + cjp->inst_lst[idx].next
228
+ CSONPATH_DO_EXTRA_ARGS_NEESTED);
229
+ CSONPATH_DO_FILTER_FIND;
230
+ } else {
231
+ fail_match:
232
+ operation = operation_in;
233
+ walker_idx = in_idx;
234
+ filter_next = filter_next_in;
245
235
  }
246
- });
236
+ }
237
+ }
247
238
  CSONPATH_DO_FILTER_OUT;
248
239
  break;
249
240
  }
@@ -255,6 +246,46 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
255
246
  CSONPATH_DO_FIND_ALL_CLEAUP;
256
247
  return tret;
257
248
  }
249
+ case CSONPATH_INST_RANGE:
250
+ {
251
+ if (!CSONPATH_IS_ARRAY(tmp)) {
252
+ return CSONPATH_NONE_FOUND_RET;
253
+ }
254
+
255
+ CSONPATH_JSON el;
256
+ intptr_t key_idx;
257
+
258
+ (void)key_idx;
259
+ int next_0 = cjp->inst_lst[idx].next;
260
+ int next_1 = cjp->inst_lst[idx + 1].next;
261
+ int next_2 = cjp->inst_lst[idx + 2].next;
262
+ unsigned int beg = csonpath_int_from_walker(cjp->inst_lst[idx + 1].inst, walker + next_0);
263
+ unsigned int end = csonpath_int_from_walker(cjp->inst_lst[idx + 2].inst,
264
+ walker + next_0 + next_1);
265
+
266
+ if (!end)
267
+ end = -1;
268
+
269
+ CSONPATH_DO_RANGE_PRE_LOOP;
270
+ CSONPATH_FOREACH_ARRAY(tmp, el, key_idx) {
271
+ if (key_idx < beg) {
272
+ key_idx = beg - 1;
273
+ continue;
274
+ }
275
+ if (key_idx >= end)
276
+ break;
277
+ CSONPATH_DO_FOREACH_PRE_SET
278
+ CSONPATH_DO_RET_TYPE tret =
279
+ csonpath_do_internal(cjp, origin, el, tmp, idx + 3,
280
+ walker + next_0 + next_1 + next_2
281
+ CSONPATH_DO_EXTRA_ARGS_NEESTED);
282
+
283
+ CSONPATH_DO_RANGE;
284
+ }
285
+
286
+ CSONPATH_DO_GET_ALL_OUT;
287
+ break;
288
+ }
258
289
  case CSONPATH_INST_GET_ALL:
259
290
  {
260
291
  CSONPATH_JSON el;
@@ -356,6 +387,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
356
387
 
357
388
  #ifndef CSONPATH_NO_UNDEF
358
389
 
390
+ #undef CSONPATH_PRE_GET_ROOT
359
391
  #undef CSONPATH_PRE_GET
360
392
  #undef CSONPATH_DO_PRE_OPERATION
361
393
  #undef CSONPATH_DO_POST_OPERATION
@@ -381,5 +413,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
381
413
  #undef CSONPATH_DO_FILTER_PRE_LOOP
382
414
  #undef CSONPATH_DO_FILTER_FIND
383
415
  #undef CSONPATH_DO_FILTER_LOOP_PRE_SET
416
+ #undef CSONPATH_DO_RANGE
417
+ #undef CSONPATH_DO_RANGE_PRE_LOOP
384
418
 
385
419
  #endif
@@ -50,6 +50,13 @@
50
50
  r; \
51
51
  })
52
52
 
53
+ #define CSONPATH_FORMAT_EXCEPTION(ARGS...) \
54
+ PyErr_Format(PyExc_ValueError, ARGS)
55
+
56
+ #define CSONPATH_EXCEPTION(ARGS...) \
57
+ PyErr_Format(PyExc_ValueError, ARGS); \
58
+ return -1;
59
+
53
60
  #define CSONPATH_CALLBACK PyObject *
54
61
 
55
62
  #define CSONPATH_CALLBACK_DATA PyObject *
@@ -84,7 +91,7 @@
84
91
  static int pydict_try_setitemstring(PyObject *obj, const char * const at, PyObject *el)
85
92
  {
86
93
  if (!PyDict_Check(obj)) {
87
- PyErr_Format(PyExc_ValueError, "Unable to follow path: Dict expected");
94
+ PyErr_Format(PyExc_ValueError, "Unable to follow path (%s): Dict expected", at);
88
95
  return -1;
89
96
  }
90
97
  PyDict_SetItemString(obj, at, el);
@@ -97,7 +104,7 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
97
104
  PyErr_Format(PyExc_ValueError, "Unable to follow path: List expected");
98
105
  return -1;
99
106
  }
100
- Py_ssize_t s = PyList_Size(array);
107
+ Py_ssize_t s = PyList_Size(array);
101
108
  if (at >= s) {
102
109
  for (;s < at; ++s)
103
110
  PyList_Insert(array, s, Py_None);
@@ -124,6 +131,33 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
124
131
  ) (array, at, el)
125
132
 
126
133
 
134
+ #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 13)
135
+ /* PyList_Clear was introduced in Python 3.13 */
136
+ #define CSONPATH_ARRAY_CLEAR(o) PyList_Clear(o)
137
+ #else
138
+ /* For older versions, manually clear the list */
139
+ #define CSONPATH_ARRAY_CLEAR(o) \
140
+ do { \
141
+ while (PyList_Size(o) > 0) { \
142
+ PyList_SetSlice(o, 0, PyList_Size(o), NULL); \
143
+ } \
144
+ } while (0)
145
+ #endif
146
+
147
+ #define CSONPATH_OBJ_CLEAR(o) PyDict_Clear(o)
148
+
149
+ #define CSONPATH_FOREACH_ARRAY(obj, child, idx) \
150
+ for (intptr_t array_len = PyList_Size(obj), idx = 0; \
151
+ ({int r = idx < array_len; if (r) child = PyList_GetItem(obj, idx); r;}); ++idx)
152
+
153
+ #define CSONPATH_FOREACH_OBJ(obj, child, key) \
154
+ for (Py_ssize_t pos_ = 0; ({ \
155
+ PyObject *key_; \
156
+ _Bool r = PyDict_Next(obj, &pos_, &key_, &child); \
157
+ if (r) key = PyUnicode_AsUTF8AndSize(key_, NULL); \
158
+ r; \
159
+ });)
160
+
127
161
  #define CSONPATH_FOREACH_EXT(obj, el, code, key_idx) \
128
162
  if (PyDict_Check(obj)) { \
129
163
  PyObject *key_; \
@@ -223,6 +257,12 @@ static PyObject *find_first(PyCsonPathObject *self, PyObject* args)
223
257
  return ret;
224
258
  }
225
259
 
260
+ static PyObject *print_instructions(PyCsonPathObject *self, PyObject *args, PyObject *kwds)
261
+ {
262
+ csonpath_print_instruction(self->cp);
263
+ return Py_None;
264
+ }
265
+
226
266
  static PyObject *callback(PyCsonPathObject *self, PyObject* args)
227
267
  {
228
268
  PyObject *json, *callback, *udata = Py_None;
@@ -266,7 +306,6 @@ static PyObject *update_or_create_callback(PyCsonPathObject *self, PyObject* arg
266
306
  return PyLong_FromLong(ret);
267
307
  }
268
308
 
269
-
270
309
  static void PyCsonPath_dealloc(PyCsonPathObject *self) {
271
310
  if (self->cp) {
272
311
  csonpath_destroy(self->cp);
@@ -289,6 +328,7 @@ static PyObject *PyCsonPath_set_path(PyCsonPathObject *self, PyObject* args) {
289
328
  static PyMethodDef csonpath_py_method[] = {
290
329
  {"set_path", (PyCFunction)PyCsonPath_set_path, METH_VARARGS, "set_path"},
291
330
  {"callback", (PyCFunction)callback, METH_VARARGS, "callback"},
331
+ {"print_instructions", (PyCFunction)print_instructions, METH_NOARGS, "print_instructions"},
292
332
  {"update_or_create_callback", (PyCFunction)update_or_create_callback, METH_VARARGS, "update_or_create_callback"},
293
333
  {"find_first", (PyCFunction)find_first, METH_VARARGS, "find first elems"},
294
334
  {"find_all", (PyCFunction)find_all, METH_VARARGS, "find all elems, if one found, pout it in an array"},
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "csonpath"
7
- version = "0.8.0"
7
+ version = "0.10.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.8.0"
25
+ current_version = "0.10.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