libsheepy
libsheepyCSmallJsonInternal.h
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2023 Remy Noulin
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 #pragma once
23 
24 
25 static smallJsonFunctionst *smallJsonF = NULL;
26 
27 #define LESSsa(i,j) (sortFCmp(&arr[i], &arr[j], compareFunction))
28 #define SWAPsa(i,j) tmp = arr[i], arr[i] = arr[j], arr[j] = tmp
29 
30 #if recycleContainers
31 #include "recycleContainers.h"
32 declareRecycle(smallJsont);
33 #endif // recycleContainers
34 
35 #define walkJsonPath(getSmallObj, arrayCode, dictCode, returnFail, directHit, keyErrorReturn)\
36  ;/*avoid error: a label can only be part of a statement and a declaration is not a statement */\
37  if (!key) {keyErrorReturn;}\
38  /* check key type */\
39  jsonPathRest keyType = keyIsSmallJson(self, key);\
40  if (keyType == NOT_A_PATH) {\
41  returnFail;\
42  directHit;\
43  }\
44 \
45  sDictt **d = &(self->top);\
46  sArrayt **a = &(self->topA);\
47  smallt **oo = NULL;\
48  int status = 0;\
49  bool escape = false;\
50  size_t keyIdx = 0;\
51 \
52  for(size_t i = 0 ; key[i] ; i++) {\
53  if (escape) {\
54  escape = false;\
55  continue;\
56  }\
57  if (key[i] == '[') {\
58  /* array index */\
59  const char *next = findS((key+i+1), "]");\
60  if (next) {\
61  size_t keyLen = (size_t)(next - (key+i+1));\
62  char *keyInPath = sliceS((key+i+1), 0, (int64_t)keyLen);\
63 \
64  if (oo) {\
65  /* oo is from the smallJson and is an array */\
66  a = (sArrayt **) oo;\
67  /* verify that d is an sArray */\
68  if ((*a)->type != ARRAY) {free(keyInPath);keyErrorReturn;}\
69  }\
70 \
71  /* check that array a exists */\
72  if (!*a) {free(keyInPath);keyErrorReturn;}\
73 \
74  int64_t idx = parseInt(keyInPath);\
75  /* convert python index (negative index) */\
76  int64_t len = (*a)->count;\
77  if (idx >= len) {free(keyInPath);keyErrorReturn;}\
78  if (idx < -len) {free(keyInPath);keyErrorReturn;}\
79  if (idx < 0) {idx = len + idx;}\
80  if (!*(next+1)) {\
81  arrayCode;\
82  free(keyInPath);\
83  break;\
84  }\
85  else {\
86  oo = sArrayGetP(*a, (uint32_t)idx);\
87  getSmallObj;\
88  }\
89  free(keyInPath);\
90  }\
91  }\
92 \
93  if (key[i] == '"') {\
94  if (status == 1) {\
95  /* found closing quote */\
96  status = 0;\
97  const char *next = key+i;\
98  size_t keyLen = i - keyIdx;\
99  char *keyInPath = sliceS((key+keyIdx), 0, (int64_t)keyLen);\
100 \
101  if (oo) {\
102  /* oo is from the smallJson and is a dict */\
103  d = (sDictt **) oo;\
104  /* verify that d is an sDict */\
105  if ((*d)->type != DICT) {free(keyInPath);keyErrorReturn;}\
106  }\
107 \
108  unescapeKey(keyInPath, keyInPath, keyLen);\
109  if (!*(next+1)) {\
110  dictCode;\
111  free(keyInPath);\
112  break;\
113  }\
114  else {\
115  oo = sDictGetP(*d, keyInPath);\
116  getSmallObj;\
117  }\
118  free(keyInPath);\
119  continue;\
120  }\
121  /* dict key */\
122  status = 1;\
123  keyIdx = i+1;\
124  }\
125  if (key[i] == '\\' && status == 1) escape = true;\
126  }\
127  UNIQVAR(walkEnd): UNUSED
128 
129 // when the path is wrong:
130 // - free the sContainer if baset is not smallContainer
131 // (it means baset was not a smallObject, it was a user class instead)
132 // - free the sObjects that not stored in a smallObject (newly allocated)
133 #define setJsonPath\
134  walkJsonPath(if (!oo) {free(keyInPath); if(isNew){free(o);} return NULL;}/*getSmallObj*/, sArraySetTiny(*a, (uint32_t)idx, o)/*arrayCode*/, sDictSetTiny(d, keyInPath, o)/*dictCode*/, /*returnFail*/, sDictSetTiny(&(self->top), key, o); return self/*directHit*/, if(isNew){free(o);} return NULL/*keyErrorReturn*/)
135 
136 // for setArrayc, the strings are newly allocated so sFree has to used instead
137 // of free to avoid memory leaks
138 #define setJsonPathsFree\
139  walkJsonPath(if (!oo) {free(keyInPath); if(isNew){sFree(o);} return NULL;}/*getSmallObj*/, sArraySetTiny(*a, (uint32_t)idx, o)/*arrayCode*/, sDictSetTiny(d, keyInPath, o)/*dictCode*/, /*returnFail*/, sDictSetTiny(&(self->top), key, o); return self/*directHit*/, if(isNew){sFree(o);} return NULL/*keyErrorReturn*/)
140 
141 #define setJsonPathWithoutReturn\
142  walkJsonPath(if (!oo) {free(keyInPath);if(isNew){free(o);}return NULL;}/*getSmallObj*/, sArraySetTiny(*a, (uint32_t)idx, o)/*arrayCode*/, sDictSetTiny(d, keyInPath, o)/*dictCode*/, /*returnFail*/, sDictSetTiny(&(self->top), key, o); goto UNIQVAR(walkEnd)/*directHit*/, if(isNew){free(o);}return NULL/*keyErrorReturn*/)
143 
144 #define setPJsonPath(objP)\
145  walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, sArraySetP(*a, (uint32_t)idx, objP)/*arrayCode*/, sDictSetP(d, keyInPath, objP)/*dictCode*/, /*returnFail*/, sDictSetP(&(self->top), key, objP); return self/*directHit*/, return NULL/*keyErrorReturn*/)
146 
147 #define setPNFreeJsonPath(objP, finishArg)\
148  walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, sArraySetP(*a, (uint32_t)idx, objP)/*arrayCode*/, sDictSetP(d, keyInPath, objP)/*dictCode*/, /*returnFail*/, sDictSetP(&(self->top), key, objP); finishArg ; return self/*directHit*/, return NULL/*keyErrorReturn*/)
149 
150 // this macro jumps to the 'fail' label when there is an error
151 // and jumps to the 'pass' label when the element is found and the o variable is set
152 #define getJsonPath\
153  walkJsonPath(if (!oo) {free(keyInPath);goto fail;} o = *oo/*getSmallObj*/, if (!*a) {free(keyInPath);goto fail;} o = sArrayGetTiny(*a, (uint32_t)idx)/*arrayCode*/, if (!*d) {free(keyInPath);goto fail;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) goto fail/*returnFail*/, o = sDictGetTiny(self->top, key); goto pass/*directHit*/, goto fail/*keyErrorReturn*/)
154 
155 #define delJsonPath\
156  walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} sArrayDelTiny(*a, (uint32_t)idx)/*arrayCode*/, if (!*d) {free(keyInPath);return NULL;} sDictDelTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return NULL/*returnFail*/, sDictDelTiny(self->top, key) ; return self/*directHit*/, return NULL/*keyErrorReturn*/)
157 
158 #define removeJsonPath\
159  walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} sArraySetShortTiny(*a, (uint32_t)idx, NULL)/*arrayCode*/, if (!*d) {free(keyInPath);return NULL;} forEachSDict(*d, e) {if (e->key && eqS(keyInPath, e->key)) { free(e->key); e->key = NULL; break;} }/*dictCode*/, if (!self->top) return NULL/*returnFail*/, forEachSDict(self->top, e) {if (e->key && eqS(key, e->key)) { free(e->key); e->key = NULL; break;} } ; return self/*directHit*/, return NULL/*keyErrorReturn*/)
160 
161 #define typeStringJsonPath\
162  walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} o = sArrayGetTiny(*a, (uint32_t)idx)/*arrayCode*/, if (!*d) {free(keyInPath);return NULL;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return NULL/*returnFail*/, o = sDictGet(self->top, key) ; if (!o) return NULL; return SMALL_TYPE_NAMES[(size_t)o->type]/*directHit*/, return NULL/*keyErrorReturn*/)
163 
164 #define typeJsonPath\
165  walkJsonPath(if (!oo) {free(keyInPath);return 0;}/*getSmallObj*/, if (!*a) {free(keyInPath);return 0;} o = sArrayGetTiny(*a, (uint32_t)idx)/*arrayCode*/, if (!*d) {free(keyInPath);return 0;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return 0/*returnFail*/, o = sDictGet(self->top, key) ; if (!o) return 0; return o->type/*directHit*/, return 0/*keyErrorReturn*/)
166 
167 #define isEJsonPath(test)\
168  walkJsonPath(if (!oo) {free(keyInPath);return 0;}/*getSmallObj*/, if (!*a) {free(keyInPath);return 0;} o = sArrayGetTiny(*a, (uint32_t)idx)/*arrayCode*/, if (!*d) {free(keyInPath);return 0;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return 0/*returnFail*/, o = sDictGet(self->top, key) ; if (!o) return false; return test/*directHit*/, return 0/*keyErrorReturn*/)
169 
170 #define mainSetJsonPathWithoutReturn(initValue, allocValue, subSetJsonPath) \
171  smallt *o = NULL;\
172  if (!key)\
173  return NULL;\
174  jsonPathRest kType = keyIsSmallJson(self, key);\
175  if (self->topIsA != SMALLJSON_IS_EMPTY && ((kType == ARRAY_PATH && self->topIsA != TOP_IS_ARRAY) || ((kType == NOT_A_PATH || kType == DICT_PATH) && self->topIsA != TOP_IS_DICT)))\
176  return NULL;\
177  initValue;\
178  switch(self->topIsA) {\
179  case SMALLJSON_IS_EMPTY:\
180  if (kType == NOT_A_PATH || kType == DICT_PATH)\
181  self->topIsA = TOP_IS_DICT;\
182  else if (kType == ARRAY_PATH)\
183  self->topIsA = TOP_IS_ARRAY;\
184  FALLTHRU;\
185  case TOP_IS_ARRAY:\
186  ;FALLTHRU;\
187  case TOP_IS_DICT:;\
188  bool isNew UNUSED = false;\
189  allocValue;\
190  subSetJsonPath;\
191  break;\
192  default:; /* do nothing */\
193  }
194 
195 
196 #define mainSetJsonPath(initValue, allocValue, subSetJsonPath) \
197  mainSetJsonPathWithoutReturn(initValue, allocValue, subSetJsonPath)\
198  return self
199