libsheepyCSmallJsonInternal.h (9883B)
1 // MIT License 2 // 3 // Copyright (c) 2026 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