libsheepy

C lib for handling text files, strings and json like data structure with an object oriented system
git clone https://spartatek.se/git/libsheepy.git
Log | Files | Refs | README | LICENSE

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