csonpath 0.9.0__tar.gz → 0.11.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.9.0
3
+ Version: 0.11.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -144,6 +144,7 @@ print(o.find_first(d)) # Output: "value"
144
144
 
145
145
  #### Avaible methodes:
146
146
  - `CsonPath(path)`: create a new csonpath object.
147
+ - `CsonPath(path, return_empty_array)`: Create a new csonpath object and return an empty list instead of None (like jsonpath-ng).
147
148
  - `OBJ.find_first(self, json)`: take a json, return first found occurrence.
148
149
  - `OBJ.find_all(self, json)`: take a json, return all found occurrence in a list.
149
150
  - `OBJ.remove(self, json)`: take a json, remove all found occurrence from it.
@@ -135,6 +135,7 @@ print(o.find_first(d)) # Output: "value"
135
135
 
136
136
  #### Avaible methodes:
137
137
  - `CsonPath(path)`: create a new csonpath object.
138
+ - `CsonPath(path, return_empty_array)`: Create a new csonpath object and return an empty list instead of None (like jsonpath-ng).
138
139
  - `OBJ.find_first(self, json)`: take a json, return first found occurrence.
139
140
  - `OBJ.find_all(self, json)`: take a json, return all found occurrence in a list.
140
141
  - `OBJ.remove(self, json)`: take a json, remove all found occurrence from it.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csonpath
3
- Version: 0.9.0
3
+ Version: 0.11.0
4
4
  Description-Content-Type: text/markdown
5
5
  License-File: LICENSE
6
6
  Provides-Extra: dev
@@ -144,6 +144,7 @@ print(o.find_first(d)) # Output: "value"
144
144
 
145
145
  #### Avaible methodes:
146
146
  - `CsonPath(path)`: create a new csonpath object.
147
+ - `CsonPath(path, return_empty_array)`: Create a new csonpath object and return an empty list instead of None (like jsonpath-ng).
147
148
  - `OBJ.find_first(self, json)`: take a json, return first found occurrence.
148
149
  - `OBJ.find_all(self, json)`: take a json, return all found occurrence in a list.
149
150
  - `OBJ.remove(self, json)`: take a json, remove all found occurrence from it.
@@ -5,6 +5,7 @@ csonpath.h
5
5
  csonpath_do.h
6
6
  csonpath_python.c
7
7
  pyproject.toml
8
+ setup.py
8
9
  csonpath.egg-info/PKG-INFO
9
10
  csonpath.egg-info/SOURCES.txt
10
11
  csonpath.egg-info/dependency_links.txt
@@ -10,7 +10,20 @@
10
10
  #endif
11
11
 
12
12
  #ifndef CSONPATH_NO_REGEX
13
- #include <regex.h>
13
+ # if defined CSONPATH_TINY_REGEX
14
+ # include <tiny-regex-c/re.h>
15
+ typedef char * csonpath_reg_t;
16
+ # elif defined CSONPATH_PCRE2
17
+ # define PCRE2_CODE_UNIT_WIDTH 8
18
+ # include <pcre2.h>
19
+ typedef pcre2_code * csonpath_reg_t;
20
+ # elif defined CSONPATH_PCRE2_POSIX
21
+ # include <pcre2posix.h>
22
+ typedef regex_t csonpath_reg_t;
23
+ # else
24
+ # include <regex.h>
25
+ typedef regex_t csonpath_reg_t;
26
+ # endif
14
27
  #endif
15
28
 
16
29
  #define CSONPATH_UNUSED __attribute__((unused))
@@ -57,6 +70,7 @@ enum csonpath_instuction_raw {
57
70
  CSONPATH_INST_FILTER_AND,
58
71
  CSONPATH_INST_GET_ALL,
59
72
  CSONPATH_INST_FIND_ALL,
73
+ CSONPATH_INST_RANGE,
60
74
  CSONPATH_INST_OR,
61
75
  CSONPATH_INST_END,
62
76
  CSONPATH_INST_BROKEN
@@ -80,6 +94,7 @@ CSONPATH_UNUSED static const char *csonpath_instuction_str[] = {
80
94
  "FILTER_AND",
81
95
  "GET_ALL",
82
96
  "FIND_ALL",
97
+ "RANGE",
83
98
  "OR",
84
99
  "END",
85
100
  "BROKEN"
@@ -107,8 +122,12 @@ struct csonpath {
107
122
  int compiled;
108
123
  #ifndef CSONPATH_NO_REGEX
109
124
  int regex_cnt;
110
- regex_t *regexs;
125
+ csonpath_reg_t *regexs;
126
+ #ifdef CSONPATH_PCRE2
127
+ pcre2_match_data **match_datas;
111
128
  #endif
129
+ #endif
130
+ int return_empty_array;
112
131
  };
113
132
 
114
133
  struct csonpath_child_info {
@@ -170,12 +189,25 @@ static inline void csonpath_destroy(struct csonpath cjp[static 1])
170
189
  free(cjp->path);
171
190
  free(cjp->inst_lst);
172
191
  free(cjp->compile_error);
192
+ #ifndef CSONPATH_NO_REGEX
173
193
  if (cjp->regex_cnt) {
194
+ #ifndef CSONPATH_TINY_REGEX
174
195
  for (int i = 0; i < cjp->regex_cnt; ++i) {
196
+ #ifdef CSONPATH_PCRE2
197
+ pcre2_code_free(cjp->regexs[i]);
198
+ pcre2_match_data_free(cjp->match_datas[i]);
199
+ #else
175
200
  regfree(&cjp->regexs[i]);
201
+ #endif
202
+
176
203
  }
204
+ #endif
205
+ #ifdef CSONPATH_PCRE2
206
+ free(cjp->match_datas);
207
+ #endif
177
208
  free(cjp->regexs);
178
209
  }
210
+ #endif
179
211
  *cjp = (struct csonpath){};
180
212
  }
181
213
 
@@ -202,6 +234,9 @@ static inline int csonpath_init(struct csonpath cjp[static 1],
202
234
  if (!cjp->path || !cjp->inst_lst) {
203
235
  return -ENOMEM;
204
236
  }
237
+
238
+ cjp->return_empty_array = 0;
239
+
205
240
  return 0;
206
241
  }
207
242
 
@@ -226,7 +261,7 @@ static inline void csonpath_push_inst_cpy(struct csonpath cjp[static 1],
226
261
  *inst_idx += 1;
227
262
  }
228
263
 
229
- static void csonpath_print_instruction(struct csonpath cjp[static 1])
264
+ static void csonpath_print_instruction(const struct csonpath cjp[const static 1])
230
265
  {
231
266
  int idx = 0;
232
267
  for (;cjp->inst_lst[idx].inst != CSONPATH_INST_END; ++idx) {
@@ -240,6 +275,43 @@ static inline _Bool csonpath_is_dot_operand(int c)
240
275
  return isalnum(c) || c == '_' || c == '-';
241
276
  }
242
277
 
278
+
279
+ static int csonpath_fill_walker_with_int(char *walker, int num, int first_ret)
280
+ {
281
+ if (num < 100) {
282
+ *walker = num;
283
+ return first_ret;
284
+ }
285
+ union {
286
+ int n;
287
+ char c[4];
288
+ } u = {.n=num};
289
+ walker[0] = u.c[0];
290
+ walker[1] = u.c[1];
291
+ walker[2] = u.c[2];
292
+ walker[3] = u.c[3];
293
+ return first_ret + 1;
294
+ }
295
+
296
+ static int csonpath_int_from_walker(int operand_instruction, char *walker)
297
+ {
298
+ switch(operand_instruction) {
299
+ case CSONPATH_INST_FILTER_OPERAND_BYTE:
300
+ case CSONPATH_INST_GET_ARRAY_SMALL:
301
+ return *walker;
302
+ case CSONPATH_INST_GET_ARRAY_BIG:
303
+ case CSONPATH_INST_FILTER_OPERAND_INT:
304
+ {
305
+ union {int n; char c[4];} to_num =
306
+ { .c= { walker[0], walker[1], walker[2], walker[3] } };
307
+ return to_num.n;
308
+ }
309
+ default:
310
+ break;
311
+ }
312
+ return -1;
313
+ }
314
+
243
315
  static int csonpath_compile(struct csonpath cjp[static 1])
244
316
  {
245
317
  char *walker = cjp->path;
@@ -397,13 +469,16 @@ static int csonpath_compile(struct csonpath cjp[static 1])
397
469
  /* = and == are the same here */
398
470
  if (to_check == '=') {
399
471
  csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_EQ, &inst_idx);
400
- if (next[0] == '=')
472
+ if (next[0] == '=') {
401
473
  ++next;
474
+ }
475
+ #ifndef CSONPATH_NO_REGEX
402
476
  else if (next[0] == '~') {
403
477
  cjp->inst_lst[inst_idx - 1].inst = CSONPATH_INST_FILTER_KEY_REG_EQ;
404
478
  regex_idx = cjp->regex_cnt++;
405
479
  ++next;
406
480
  }
481
+ #endif
407
482
  } else if (to_check == '!' && next[0] == '=') {
408
483
  csonpath_push_inst(cjp, CSONPATH_INST_FILTER_KEY_NOT_EQ, &inst_idx);
409
484
  ++next;
@@ -445,14 +520,38 @@ static int csonpath_compile(struct csonpath cjp[static 1])
445
520
  *next = 0;
446
521
  #ifndef CSONPATH_NO_REGEX
447
522
  if (regex_idx >= 0) {
448
- if (!regex_idx)
523
+ if (!regex_idx) {
449
524
  cjp->regexs = malloc(sizeof *cjp->regexs * 255);
450
- int e = regcomp(&cjp->regexs[regex_idx], walker, 0);
525
+ #ifdef CSONPATH_PCRE2
526
+ cjp->match_datas = malloc(sizeof *cjp->match_datas * 255);
527
+ #endif
528
+ }
451
529
  cjp->inst_lst[inst_idx - 1].regex_idx = regex_idx;
530
+ # if defined CSONPATH_TINY_REGEX
531
+ cjp->regexs[regex_idx] = walker;
532
+ # elif defined CSONPATH_PCRE2
533
+ int errorcode;
534
+ PCRE2_SIZE erroroffset;
535
+
536
+ cjp->regexs[regex_idx] = pcre2_compile((unsigned char *)walker,
537
+ PCRE2_ZERO_TERMINATED, 0,
538
+ &errorcode, &erroroffset, NULL);
539
+ if (!cjp->regexs[regex_idx]) {
540
+ PCRE2_UCHAR buffer[256];
541
+ pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
542
+ CSONPATH_COMPILE_ERR(tmp, next - orig, "regex has error: \"%s\"\n", buffer);
543
+ goto error;
544
+ }
545
+ cjp->match_datas[regex_idx] = pcre2_match_data_create_from_pattern(cjp->regexs[regex_idx],
546
+ NULL);
547
+ pcre2_jit_compile(cjp->regexs[regex_idx], PCRE2_JIT_COMPLETE);
548
+ # else
549
+ int e = regcomp(&cjp->regexs[regex_idx], walker, 0);
452
550
  if (e) {
453
551
  CSONPATH_COMPILE_ERR(tmp, next - orig, "regex has error\n");
454
552
  goto error;
455
553
  }
554
+ # endif
456
555
  }
457
556
  #endif
458
557
  ++next;
@@ -479,20 +578,8 @@ static int csonpath_compile(struct csonpath cjp[static 1])
479
578
 
480
579
  n = atoi(walker);
481
580
  to_check = *next;
482
- if (n < 100) {
483
- *walker = n;
484
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_BYTE, &inst_idx);
485
- } else {
486
- union {
487
- int n;
488
- char c[4];
489
- } u = {.n=n};
490
- walker[0] = u.c[0];
491
- walker[1] = u.c[1];
492
- walker[2] = u.c[2];
493
- walker[3] = u.c[3];
494
- csonpath_push_inst(cjp, CSONPATH_INST_FILTER_OPERAND_INT, &inst_idx);
495
- }
581
+ csonpath_push_inst(cjp, csonpath_fill_walker_with_int(
582
+ walker, n, CSONPATH_INST_FILTER_OPERAND_BYTE), &inst_idx);
496
583
  }
497
584
 
498
585
  /* skip space */
@@ -537,11 +624,23 @@ static int csonpath_compile(struct csonpath cjp[static 1])
537
624
 
538
625
  next = walker;
539
626
  do {
540
- if (*next < '0' || *next > '9') {
541
- CSONPATH_COMPILE_ERR(tmp, walker - orig,
542
- "unexpected '%c', sting, filter or number require\n", *next);
543
- }
544
- next++;
627
+ if (*next == ':') {
628
+ csonpath_push_inst(cjp, CSONPATH_INST_RANGE, &inst_idx);
629
+ num = atoi(walker);
630
+ csonpath_push_inst(
631
+ cjp, csonpath_fill_walker_with_int(
632
+ walker, num, CSONPATH_INST_GET_ARRAY_SMALL),
633
+ &inst_idx);
634
+ cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
635
+ walker = next + 1;
636
+ ++next;
637
+ continue;
638
+ }
639
+ if (*next < '0' || *next > '9') {
640
+ CSONPATH_COMPILE_ERR(tmp, walker - orig,
641
+ "unexpected '%c', sting, filter or number require\n", *next);
642
+ }
643
+ next++;
545
644
  } while (*next && *next != ']');
546
645
  if (!*next) {
547
646
  CSONPATH_COMPILE_ERR(tmp, walker - orig,
@@ -549,20 +648,9 @@ static int csonpath_compile(struct csonpath cjp[static 1])
549
648
  }
550
649
  *next = 0;
551
650
  num = atoi(walker);
552
- if (num < 100) {
553
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_SMALL, &inst_idx);
554
- *walker = num;
555
- } else {
556
- union {
557
- int n;
558
- char c[4];
559
- } u = {.n=num};
560
- walker[0] = u.c[0];
561
- walker[1] = u.c[1];
562
- walker[2] = u.c[2];
563
- walker[3] = u.c[3];
564
- csonpath_push_inst(cjp, CSONPATH_INST_GET_ARRAY_BIG, &inst_idx);
565
- }
651
+ csonpath_push_inst(cjp, csonpath_fill_walker_with_int(
652
+ walker, num, CSONPATH_INST_GET_ARRAY_SMALL),
653
+ &inst_idx);
566
654
  cjp->inst_lst[inst_idx - 1].next = next - walker + 1;
567
655
  walker = next + 1;
568
656
  to_check = *walker;
@@ -615,7 +703,7 @@ static int csonpath_compile(struct csonpath cjp[static 1])
615
703
  csonpath_push_inst(cjp, inst, &inst_idx);
616
704
  to_check = *walker;
617
705
  goto again;
618
- }
706
+ }
619
707
  for (next = walker; csonpath_is_dot_operand(*next); ++next);
620
708
  if (next == walker) {
621
709
  if (*next == '[')
@@ -656,19 +744,6 @@ static int csonpath_compile(struct csonpath cjp[static 1])
656
744
  return -1;
657
745
  }
658
746
 
659
- static int csonpath_int_from_walker(int operand_instruction, char *walker)
660
- {
661
- if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_BYTE)
662
- return *walker;
663
- else if (operand_instruction == CSONPATH_INST_FILTER_OPERAND_INT) {
664
- union {int n; char c[4];} to_num =
665
- { .c= { walker[0], walker[1], walker[2], walker[3] } };
666
-
667
- return to_num.n;
668
- }
669
- return -1;
670
- }
671
-
672
747
  static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char *owalker)
673
748
  {
674
749
  switch (operand_instruction) {
@@ -687,12 +762,11 @@ static _Bool csonpath_do_match(int operand_instruction, CSONPATH_JSON el2, char
687
762
  return 0;
688
763
  }
689
764
 
690
- static CSONPATH_JSON cosnpath_crawl_filter_el(struct csonpath cjp[static 1],
765
+ static CSONPATH_JSON cosnpath_crawl_filter_el(const struct csonpath cjp[const static 1],
691
766
  int *idx, char **owalker,
692
767
  CSONPATH_JSON el2,
693
768
  int filter_next)
694
769
  {
695
-
696
770
  for (; *idx < filter_next; ++(*idx)) {
697
771
  switch (cjp->inst_lst[*idx].inst) {
698
772
  case CSONPATH_INST_GET_OBJ:
@@ -709,12 +783,12 @@ static CSONPATH_JSON cosnpath_crawl_filter_el(struct csonpath cjp[static 1],
709
783
  }
710
784
 
711
785
 
712
- static _Bool csonpath_make_match(struct csonpath cjp[static 1],
786
+ static _Bool csonpath_make_match(const struct csonpath cjp[const static 1],
713
787
  struct csonpath_instruction inst[static 1],
714
788
  CSONPATH_JSON el2, char *owalker, int operation)
715
789
  {
716
790
  int operand_instruction = inst->inst;
717
-
791
+
718
792
  if (el2 == CSONPATH_NULL)
719
793
  return 0;
720
794
  _Bool match = 0;
@@ -738,16 +812,38 @@ static _Bool csonpath_make_match(struct csonpath cjp[static 1],
738
812
  CSONPATH_GET_NUM(el2);
739
813
  break;
740
814
  case CSONPATH_INST_FILTER_KEY_REG_EQ:
741
- #ifdef CSONPATH_NO_REGEX
742
- CSONPATH_GETTER_ERR("regex deactivate\n");
743
- return CSONPATH_NONE_FOUND_RET;
815
+ #if defined CSONPATH_NO_REGEX
816
+ fprintf(stderr, "regex deactivate");
817
+ return 0;
744
818
  #else
745
819
  if (CSONPATH_IS_STR(el2)) {
746
820
  int regex_idx = inst->regex_idx;
821
+ #if defined CSONPATH_TINY_REGEX
822
+ int match_len = 0;
823
+ const char *str = CSONPATH_GET_STR(el2);
824
+ re_match(cjp->regexs[regex_idx], str, &match_len);
825
+ match = !!match_len;
826
+ #elif defined CSONPATH_PCRE2
827
+ const unsigned char *str = (const unsigned char *)CSONPATH_GET_STR(el2);
828
+ int ret = pcre2_match(cjp->regexs[regex_idx], str, PCRE2_ZERO_TERMINATED, 0,
829
+ 0, cjp->match_datas[regex_idx], NULL);
830
+
831
+ if (ret >= 0) {
832
+ // match found
833
+ return 1;
834
+ } else if (ret == PCRE2_ERROR_NOMATCH) {
835
+ // no match
836
+ return 0;
837
+ } else {
838
+ fprintf(stderr, "pcre2 match error: %d\n", ret);
839
+ return 0;
840
+ }
841
+ #else
747
842
  regex_t *compiled = &cjp->regexs[regex_idx];
748
843
  int match_len = regexec(compiled, CSONPATH_GET_STR(el2),
749
844
  0, NULL, 0);
750
845
  match = match_len == 0;
846
+ #endif
751
847
  }
752
848
  break;
753
849
  #endif
@@ -801,7 +897,7 @@ need_reloop_in = 0;
801
897
  #define CSONPATH_DO_FUNC_NAME find_first
802
898
  #define CSONPATH_DO_RETURN return tmp
803
899
 
804
- #define CSONPATH_DO_FIND_ALL return tret
900
+ #define CSONPATH_DO_FIND_ALL if (tret) return tret
805
901
 
806
902
  #define CSONPATH_DO_FILTER_FIND return tret
807
903
 
@@ -830,7 +926,7 @@ need_reloop_in = 0;
830
926
  #define CSONPATH_DO_FILTER_FIND CSONPATH_DO_FIND_ALL
831
927
 
832
928
  #define CSONPATH_DO_FIND_ALL_OUT \
833
- if (!nb_res) { \
929
+ if (!cjp->return_empty_array && !nb_res) { \
834
930
  return CSONPATH_NONE_FOUND_RET; \
835
931
  } \
836
932
  return ret_ar;
@@ -838,7 +934,6 @@ need_reloop_in = 0;
838
934
  #define CSONPATH_DO_EXTRA_ARGS_IN , ret_ar
839
935
  #define CSONPATH_DO_EXTRA_DECLATION , CSONPATH_FIND_ALL_RET ret_ar
840
936
 
841
-
842
937
  #include "csonpath_do.h"
843
938
 
844
939
  /* Delete */
@@ -881,15 +976,26 @@ need_reloop_in = 0;
881
976
  #define CSONPATH_DO_FILTER_FIND nb_res += tret;
882
977
 
883
978
  #define CSONPATH_DO_FIND_ALL ({ \
884
- if (tret < 0) return -1; \
885
- nb_res += tret; \
886
- if (need_reloop_in){ goto again; }; \
887
- })
979
+ if (tret < 0) return -1; \
980
+ nb_res += tret; \
981
+ if (need_reloop_in){ goto again; }; \
982
+ })
983
+
984
+ #define CSONPATH_DO_RANGE ({ \
985
+ if (tret < 0) return -1; \
986
+ nb_res += tret; \
987
+ --end; \
988
+ if (need_reloop_in){ goto range_again; }; \
989
+ })
888
990
 
889
991
  #define CSONPATH_DO_EXTRA_DECLATION , struct csonpath_child_info child_info, int *need_reloop
890
992
 
891
993
  #define CSONPATH_DO_EXTRA_ARGS_IN , (struct csonpath_child_info) {.type = CSONPATH_NONE}, NULL
892
994
 
995
+ #define CSONPATH_DO_RANGE_PRE_LOOP \
996
+ int need_reloop_in; \
997
+ range_again:
998
+
893
999
  #define CSONPATH_DO_FILTER_PRE_LOOP \
894
1000
  int need_reloop_in;
895
1001
 
@@ -979,12 +1085,13 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
979
1085
  #define CSONPATH_PRE_GET_ROOT \
980
1086
  int to_check = cjp->inst_lst[idx + 1].inst; \
981
1087
  if (to_check == CSONPATH_INST_END || to_check == CSONPATH_INST_OR) { \
982
- if (CSONPATH_IS_OBJ(origin) && CSONPATH_IS_OBJ(to_update)) \
1088
+ if (CSONPATH_IS_OBJ(origin) && CSONPATH_IS_OBJ(to_update)) { \
983
1089
  return csonpath_sync_root_obj(origin, to_update); \
984
- else if (CSONPATH_IS_ARRAY(origin) && CSONPATH_IS_ARRAY(to_update)) \
1090
+ } else if (CSONPATH_IS_ARRAY(origin) && CSONPATH_IS_ARRAY(to_update)) { \
985
1091
  return csonpath_sync_root_array(origin, to_update); \
986
- else \
1092
+ } else { \
987
1093
  CSONPATH_EXCEPTION("can't upate root ($)\n"); \
1094
+ } \
988
1095
  }
989
1096
 
990
1097
  #define CSONPATH_PRE_GET(this_idx) \
@@ -1046,17 +1153,16 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
1046
1153
  #define CSONPATH_DO_RETURN \
1047
1154
  if (tmp == value) { \
1048
1155
  *need_reloop = 1; \
1049
- CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); \
1050
- return 1; \
1051
1156
  } \
1052
- return 0;
1157
+ CSONPATH_CALL_CALLBACK(callback, ctx, child_info, tmp, udata); \
1158
+ return 1;
1053
1159
 
1054
1160
  #define CSONPATH_DO_EXTRA_ARGS_FIND_ALL , callback, udata, NULL, need_reloop
1055
1161
  #define CSONPATH_DO_EXTRA_ARGS_NEESTED , callback, udata, \
1056
1162
  csonpath_child_info_set(&(struct csonpath_child_info ){}, tmp, (intptr_t)key_idx), \
1057
1163
  &need_reloop_in
1058
1164
  #define CSONPATH_DO_EXTRA_ARGS , CSONPATH_CALLBACK callback, CSONPATH_CALLBACK_DATA udata
1059
- #define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, NULL, NULL
1165
+ #define CSONPATH_DO_EXTRA_ARGS_IN , callback, udata, &(struct csonpath_child_info ){}, NULL
1060
1166
  #define CSONPATH_DO_EXTRA_DECLATION CSONPATH_DO_EXTRA_ARGS, struct csonpath_child_info *child_info, int *need_reloop
1061
1167
  #define CSONPATH_DO_FIND_ALL nb_res += tret;
1062
1168
  #define CSONPATH_DO_FILTER_FIND CSONPATH_GOTO_ON_RELOOP(filter_again)
@@ -1075,19 +1181,8 @@ static int csonpath_sync_root_obj(CSONPATH_JSON parent, CSONPATH_JSON to_update)
1075
1181
  }
1076
1182
 
1077
1183
  #define CSONPATH_PRE_GET(this_idx) \
1078
- int check_at = idx + 1; \
1079
- int to_check; \
1080
- do { \
1081
- to_check = cjp->inst_lst[check_at].inst; \
1082
- ++check_at; \
1083
- } while (to_check == CSONPATH_INST_GET_ALL || to_check == CSONPATH_INST_FIND_ALL); \
1084
- if (to_check == CSONPATH_INST_END || to_check == CSONPATH_INST_OR) { \
1085
- CSONPATH_CALL_CALLBACK( \
1086
- callback, ctx, \
1087
- csonpath_child_info_set(&(struct csonpath_child_info ){}, \
1088
- ctx, (intptr_t)this_idx), tmp, udata); \
1089
- return 1; \
1090
- }
1184
+ int to_check = cjp->inst_lst[idx].inst; \
1185
+ csonpath_child_info_set(child_info, ctx, (intptr_t)this_idx)
1091
1186
 
1092
1187
 
1093
1188
  #define CSONPATH_DO_GET_NOTFOUND(this_idx) \
@@ -93,6 +93,18 @@
93
93
  #define CSONPATH_DO_FILTER_LOOP_PRE_SET
94
94
  #endif
95
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
+
96
108
  #ifndef CAT
97
109
  # define CATCAT(a, b, c) a ## b ## c
98
110
  # define CAT(a, b) a ## b
@@ -101,7 +113,7 @@
101
113
  #define csonpath_do_internal__(name) CATCAT(csonpath_, name, _internal)
102
114
  #define csonpath_do_internal csonpath_do_internal__(CSONPATH_DO_FUNC_NAME)
103
115
 
104
- static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
116
+ static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const static 1],
105
117
  CSONPATH_JSON origin,
106
118
  CSONPATH_JSON value,
107
119
  CSONPATH_JSON ctx,
@@ -113,7 +125,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
113
125
  #define csonpath_do_dotdot csonpath_do_dotdot__(CSONPATH_DO_FUNC_NAME)
114
126
 
115
127
 
116
- static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(struct csonpath cjp[static 1],
128
+ static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(const struct csonpath cjp[const static 1],
117
129
  CSONPATH_JSON origin,
118
130
  CSONPATH_JSON tmp,
119
131
  CSONPATH_JSON ctx,
@@ -123,12 +135,17 @@ static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(struct csonpath cjp[static 1],
123
135
  CSONPATH_JSON el;
124
136
  CSONPATH_DO_DECLARATION;
125
137
  const int is_obj = CSONPATH_IS_OBJ(tmp);
138
+ intptr_t key_idx;
126
139
  CSONPATH_DO_RET_TYPE tret = CSONPATH_NONE_FOUND_RET;
127
140
 
128
141
  CSONPATH_DO_FIND_ALL_PRE_LOOP;
129
- CSONPATH_FOREACH(tmp, el, {
142
+ if (is_obj) {
143
+ const char *key;
144
+ CSONPATH_FOREACH_OBJ(tmp, el, key) {
145
+ key_idx = (intptr_t)key;
146
+ (void)key_idx;
130
147
  CSONPATH_DO_FOREACH_PRE_SET;
131
- if (is_obj && !strcmp((char *)key_idx, walker)) {
148
+ if (!strcmp(key, walker)) {
132
149
  tret = csonpath_do_internal(cjp, origin, el, tmp, idx,
133
150
  walker + cjp->inst_lst[idx].next
134
151
  CSONPATH_DO_EXTRA_ARGS_NEESTED);
@@ -139,12 +156,22 @@ static CSONPATH_DO_RET_TYPE csonpath_do_dotdot(struct csonpath cjp[static 1],
139
156
  CSONPATH_DO_EXTRA_ARGS_NEESTED);
140
157
  CSONPATH_DO_FIND_ALL;
141
158
  }
142
- })
159
+ }
160
+ } else {
161
+ CSONPATH_FOREACH_ARRAY(tmp, el, key_idx) {
162
+ CSONPATH_DO_FOREACH_PRE_SET;
163
+ if (CSONPATH_IS_OBJ(el) || CSONPATH_IS_ARRAY(el)) {
164
+ tret = csonpath_do_dotdot(cjp, origin, el, tmp, idx, walker
165
+ CSONPATH_DO_EXTRA_ARGS_NEESTED);
166
+ CSONPATH_DO_FIND_ALL;
167
+ }
168
+ }
169
+ }
143
170
  CSONPATH_DO_FIND_ALL_OUT;
144
171
  return tret;
145
172
  }
146
173
 
147
- static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
174
+ static CSONPATH_DO_RET_TYPE csonpath_do_internal(const struct csonpath cjp[const static 1],
148
175
  CSONPATH_JSON origin,
149
176
  CSONPATH_JSON value,
150
177
  CSONPATH_JSON ctx,
@@ -228,11 +255,55 @@ static CSONPATH_DO_RET_TYPE csonpath_do_internal(struct csonpath cjp[static 1],
228
255
  }
229
256
  case CSONPATH_INST_FIND_ALL:
230
257
  {
231
- CSONPATH_DO_RET_TYPE tret =
232
- csonpath_do_dotdot(cjp, origin, tmp, ctx, idx + 1,
233
- walker CSONPATH_DO_EXTRA_ARGS_FIND_ALL);
234
- CSONPATH_DO_FIND_ALL_CLEAUP;
235
- return tret;
258
+ if (CSONPATH_IS_OBJ(tmp) || CSONPATH_IS_ARRAY(tmp)) {
259
+ CSONPATH_DO_RET_TYPE tret =
260
+ csonpath_do_dotdot(cjp, origin, tmp, ctx, idx + 1,
261
+ walker CSONPATH_DO_EXTRA_ARGS_FIND_ALL);
262
+ CSONPATH_DO_FIND_ALL_CLEAUP;
263
+ return tret;
264
+ } else {
265
+ return CSONPATH_NONE_FOUND_RET;
266
+ }
267
+ }
268
+ case CSONPATH_INST_RANGE:
269
+ {
270
+ if (!CSONPATH_IS_ARRAY(tmp)) {
271
+ return CSONPATH_NONE_FOUND_RET;
272
+ }
273
+
274
+ CSONPATH_JSON el;
275
+ intptr_t key_idx;
276
+
277
+ (void)key_idx;
278
+ int next_0 = cjp->inst_lst[idx].next;
279
+ int next_1 = cjp->inst_lst[idx + 1].next;
280
+ int next_2 = cjp->inst_lst[idx + 2].next;
281
+ unsigned int beg = csonpath_int_from_walker(cjp->inst_lst[idx + 1].inst, walker + next_0);
282
+ unsigned int end = csonpath_int_from_walker(cjp->inst_lst[idx + 2].inst,
283
+ walker + next_0 + next_1);
284
+
285
+ if (!end)
286
+ end = -1;
287
+
288
+ CSONPATH_DO_RANGE_PRE_LOOP;
289
+ CSONPATH_FOREACH_ARRAY(tmp, el, key_idx) {
290
+ if (key_idx < beg) {
291
+ key_idx = beg - 1;
292
+ continue;
293
+ }
294
+ if (key_idx >= end)
295
+ break;
296
+ CSONPATH_DO_FOREACH_PRE_SET
297
+ CSONPATH_DO_RET_TYPE tret =
298
+ csonpath_do_internal(cjp, origin, el, tmp, idx + 3,
299
+ walker + next_0 + next_1 + next_2
300
+ CSONPATH_DO_EXTRA_ARGS_NEESTED);
301
+
302
+ CSONPATH_DO_RANGE;
303
+ }
304
+
305
+ CSONPATH_DO_GET_ALL_OUT;
306
+ break;
236
307
  }
237
308
  case CSONPATH_INST_GET_ALL:
238
309
  {
@@ -330,7 +401,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
330
401
 
331
402
  CSONPATH_DO_POST_OPERATION;
332
403
 
333
- return ret;
404
+ return ret;
334
405
  }
335
406
 
336
407
  #ifndef CSONPATH_NO_UNDEF
@@ -361,5 +432,7 @@ static CSONPATH_DO_RET_TYPE csonpath_do_(struct csonpath cjp[static 1],
361
432
  #undef CSONPATH_DO_FILTER_PRE_LOOP
362
433
  #undef CSONPATH_DO_FILTER_FIND
363
434
  #undef CSONPATH_DO_FILTER_LOOP_PRE_SET
435
+ #undef CSONPATH_DO_RANGE
436
+ #undef CSONPATH_DO_RANGE_PRE_LOOP
364
437
 
365
438
  #endif
@@ -1,4 +1,5 @@
1
1
  #include <Python.h>
2
+ #include <stdio.h>
2
3
 
3
4
  #define CSONPATH_JSON PyObject *
4
5
 
@@ -27,7 +28,6 @@
27
28
 
28
29
  #define CSONPATH_DECREF(obj) \
29
30
  Py_DECREF(obj);
30
-
31
31
 
32
32
  #define CSONPATH_GET_NUM(obj) \
33
33
  PyLong_AsLong(obj)
@@ -131,11 +131,30 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
131
131
  ) (array, at, el)
132
132
 
133
133
 
134
+ #ifdef __TINYC__
135
+ #define CSONPATH_PRAGMA(...)
136
+ #else
137
+ #define CSONPATH_PRAGMA(...) _Pragma(__VA_ARGS__)
138
+ #endif
139
+
140
+
141
+ #if PY_MAJOR_VERSION > 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 13)
142
+ /* PyList_Clear was introduced in Python 3.13 */
134
143
  #define CSONPATH_ARRAY_CLEAR(o) PyList_Clear(o)
144
+ #else
145
+ /* For older versions, manually clear the list */
146
+ #define CSONPATH_ARRAY_CLEAR(o) \
147
+ do { \
148
+ while (PyList_Size(o) > 0) { \
149
+ PyList_SetSlice(o, 0, PyList_Size(o), NULL); \
150
+ } \
151
+ } while (0)
152
+ #endif
135
153
 
136
154
  #define CSONPATH_OBJ_CLEAR(o) PyDict_Clear(o)
137
155
 
138
156
  #define CSONPATH_FOREACH_ARRAY(obj, child, idx) \
157
+ CSONPATH_PRAGMA("GCC unroll 8") \
139
158
  for (intptr_t array_len = PyList_Size(obj), idx = 0; \
140
159
  ({int r = idx < array_len; if (r) child = PyList_GetItem(obj, idx); r;}); ++idx)
141
160
 
@@ -158,6 +177,7 @@ static int python_set_or_insert_item(PyObject *array, Py_ssize_t at, PyObject *
158
177
  } \
159
178
  } else if (PyList_Check(obj)) { \
160
179
  int array_len_ = PyList_Size(obj); \
180
+ CSONPATH_PRAGMA("GCC unroll 8") \
161
181
  for (intptr_t key_idx = 0; key_idx < array_len_; ++key_idx) { \
162
182
  el = PyList_GetItem(obj, key_idx); \
163
183
  code \
@@ -196,33 +216,53 @@ typedef struct {
196
216
 
197
217
 
198
218
  static PyObject *PyCsonPath_new(PyTypeObject *subtype, PyObject* args,
199
- PyObject* dont_care)
219
+ PyObject* kwargs)
200
220
  {
201
- PyCsonPathObject *self = (PyCsonPathObject *)subtype->tp_alloc(subtype, 0);
202
- const char *s;
203
-
204
- if (!self)
205
- BAD_ARG();
206
-
207
- if (!PyArg_ParseTuple(args, "s", &s))
208
- BAD_ARG();
209
-
210
- struct csonpath *ret = malloc(sizeof *ret);
211
- if (!self)
212
- return PyErr_NoMemory();
213
-
214
- if (csonpath_init(ret, s) < 0)
215
- return PyErr_NoMemory();
216
-
217
- if (csonpath_compile(ret) < 0) {
218
- char *error = ret->compile_error;
219
- PyErr_Format(PyExc_ValueError, "compilation fail %s", error ? error : "(unknow error)");
220
- csonpath_destroy(ret);
221
- return NULL;
222
- }
223
- self->cp = ret;
224
-
225
- return (PyObject *)self;
221
+ static char *kwlist[] = {"path", "return_empty_array", NULL};
222
+ PyCsonPathObject *self = (PyCsonPathObject *)subtype->tp_alloc(subtype, 0);
223
+ const char *s;
224
+ int return_empty_array = 0;
225
+ struct csonpath *ret = NULL;
226
+ PyObject *py_ret = NULL;
227
+
228
+ if (!self)
229
+ BAD_ARG();
230
+
231
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|p", kwlist,
232
+ &s, &return_empty_array)) {
233
+ goto error;
234
+ }
235
+
236
+ ret = malloc(sizeof *ret);
237
+ if (!ret) {
238
+ PyErr_NoMemory();
239
+ goto error;
240
+ }
241
+
242
+ if (csonpath_init(ret, s) < 0) {
243
+ py_ret = PyErr_NoMemory();
244
+ goto error_free_ret;
245
+ }
246
+
247
+ ret->return_empty_array = return_empty_array;
248
+
249
+ if (csonpath_compile(ret) < 0) {
250
+ char *err_str = ret->compile_error;
251
+ PyErr_Format(PyExc_ValueError, "compilation fail %s",
252
+ err_str ? err_str : "(unknow error)");
253
+ goto error_destroy_ret;
254
+ }
255
+
256
+ self->cp = ret;
257
+ return (PyObject *)self;
258
+
259
+ error_destroy_ret:
260
+ csonpath_destroy(ret);
261
+ error_free_ret:
262
+ free(ret);
263
+ error:
264
+ Py_DECREF(self);
265
+ return py_ret;
226
266
  }
227
267
 
228
268
  static PyObject *find_all(PyCsonPathObject *self, PyObject* args)
@@ -230,8 +270,10 @@ static PyObject *find_all(PyCsonPathObject *self, PyObject* args)
230
270
  PyObject *json;
231
271
 
232
272
  if (!PyArg_ParseTuple(args, "O", &json))
233
- BAD_ARG();
273
+ BAD_ARG();
274
+
234
275
  PyObject *ret = csonpath_find_all(self->cp, json);
276
+
235
277
  return ret;
236
278
  }
237
279
 
@@ -240,8 +282,10 @@ static PyObject *find_first(PyCsonPathObject *self, PyObject* args)
240
282
  PyObject *json;
241
283
 
242
284
  if (!PyArg_ParseTuple(args, "O", &json))
243
- BAD_ARG();
285
+ BAD_ARG();
286
+
244
287
  PyObject *ret = csonpath_find_first(self->cp, json);
288
+
245
289
  Py_INCREF(ret);
246
290
  return ret;
247
291
  }
@@ -4,14 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "csonpath"
7
- version = "0.9.0"
7
+ version = "0.11.0"
8
8
  readme = "README.md"
9
9
 
10
10
  [tool.setuptools]
11
11
  packages = [] # no Python packages, just an extension
12
- ext-modules = [
13
- {name="csonpath", sources = ["csonpath_python.c"]}
14
- ]
12
+ # Extension module is defined in setup.py for platform-specific sources
15
13
 
16
14
  [project.optional-dependencies]
17
15
  dev = [
@@ -22,7 +20,7 @@ dev = [
22
20
  testpaths = ["tests/python"]
23
21
 
24
22
  [tool.bumpversion]
25
- current_version = "0.9.0"
23
+ current_version = "0.11.0"
26
24
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
27
25
  serialize = ["{major}.{minor}.{patch}"]
28
26
  search = "{current_version}"
@@ -0,0 +1,33 @@
1
+ import platform
2
+ import os
3
+ import sys
4
+ from setuptools import setup, Extension
5
+
6
+ # Force MinGW compiler on Windows
7
+ if platform.system() == "Windows":
8
+ # Set compiler before importing distutils
9
+ os.environ["CC"] = "gcc"
10
+ # Override distutils to use MinGW
11
+ from distutils.cygwinccompiler import Mingw32CCompiler
12
+ from distutils import sysconfig
13
+ sysconfig.get_config_vars()["CC"] = "gcc"
14
+
15
+ # Base sources
16
+ sources = ["csonpath_python.c"]
17
+ extra_compile_args=["-O3", "-I./"]
18
+
19
+ # On Windows, include tiny_regex.c for regex support
20
+ if platform.system() == "Windows":
21
+ sources.append("tiny-regex-c/re.c")
22
+ extra_compile_args.append("-DCSONPATH_TINY_REGEX")
23
+ extra_compile_args.append("-I./tiny-regex-c/")
24
+
25
+ extension = Extension(
26
+ "csonpath",
27
+ sources=sources,
28
+ extra_compile_args=extra_compile_args,
29
+ )
30
+
31
+ setup(
32
+ ext_modules=[extension],
33
+ )
File without changes
File without changes
File without changes