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

commit 25a42e388d2c55c45e994c5b4ff516122fad8593
parent 62f9b67456ede24a390d8918d943718a007c2c16
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun,  7 Jul 2019 14:39:55 +0200

add support array and negative indexes in json paths, add isIntOdd, isIntEven, cBa, BSLH and macros for casting numbers (I64, F64,...)

completion.txt                         |   14 +
documentation.md                       |   52 +-
release/json/libsheepyCSmallJson.h     |  111 ++-
release/libsheepy.c                    |    2 +-
release/libsheepy.h                    |   22 +-
release/libsheepyObject.h              |    6 +
src/json/libsheepyCSmallJson.c         | 1293 +++++++++-----------------------
src/json/libsheepyCSmallJson.h         |  111 ++-
src/json/libsheepyCSmallJsonInternal.h |   93 ++-
src/json/libsheepyObjectTest.c         |   92 ++-
src/libsheepy.c                        |    2 +-
src/libsheepy.h                        |   22 +-
src/libsheepyObject.h                  |    6 +
13 files changed, 845 insertions(+), 981 deletions(-)

Diffstat:
Mcompletion.txt | 14++++++++++++++
Mdocumentation.md | 52+++++++++++++++++++++++++++++++++++++++++++++-------
Mrelease/json/libsheepyCSmallJson.h | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mrelease/libsheepy.c | 2+-
Mrelease/libsheepy.h | 22+++++++++++++++++++++-
Mrelease/libsheepyObject.h | 6++++++
Msrc/json/libsheepyCSmallJson.c | 1293++++++++++++++++++++++---------------------------------------------------------
Msrc/json/libsheepyCSmallJson.h | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/json/libsheepyCSmallJsonInternal.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/json/libsheepyObjectTest.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/libsheepy.c | 2+-
Msrc/libsheepy.h | 22+++++++++++++++++++++-
Msrc/libsheepyObject.h | 6++++++
13 files changed, 845 insertions(+), 981 deletions(-)

diff --git a/completion.txt b/completion.txt @@ -44,6 +44,16 @@ u32 u64 f32 f64 +I8(value) +I16(value) +I32(value) +I64(value) +U8(value) +U16(value) +U32(value) +U64(value) +F32(value) +F64(value) MAX(a, b) MIN(a, b) MIN3(a, b, c) @@ -64,6 +74,8 @@ maxV(a, b) minV(a, b) absV(a) FIELD_SIZEOF(t, f) +isIntOdd(value) +isIntEven(value) typ ret elif @@ -2617,6 +2629,7 @@ toUnsignedType(var) convertToUnsignedType(var) castS(casted, toCast) _ +BSLH ssGet(obj) sjGet(obj) replaceSO_max(obj,olds,news) @@ -2969,6 +2982,7 @@ aLoad(obj) aCompareExchangeStrong(obj, expected, desired) aFetchAdd(obj, valueToAdd) aFetchSub(obj, valueToSub) +#if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4) aStaticArrayT(typeName, element, MAXCOUNT) aStaticArrayInit(name) aStaticArrayAcquire(name) diff --git a/documentation.md b/documentation.md @@ -73,6 +73,16 @@ u32 u64 f32 f64 +I8(value) +I16(value) +I32(value) +I64(value) +U8(value) +U16(value) +U32(value) +U64(value) +F32(value) +F64(value) MAX(a, b) MIN(a, b) MIN3(a, b, c) @@ -93,6 +103,8 @@ maxV(a, b) minV(a, b) absV(a) FIELD_SIZEOF(t, f) +isIntOdd(value) +isIntEven(value) typ ret elif @@ -1477,6 +1489,19 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; #define u64 uint64_t #define f32 float #define f64 double +/* + * type cast + */ +#define I8(value) (i8)(value) +#define I16(value) (i16)(value) +#define I32(value) (i32)(value) +#define I64(value) (i64)(value) +#define U8(value) (u8)(value) +#define U16(value) (u16)(value) +#define U32(value) (u32)(value) +#define U64(value) (u64)(value) +#define F32(value) (f32)(value) +#define F64(value) (f64)(value) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN3(a, b, c) MIN((typeof(a))MIN(a, b), c) @@ -1541,6 +1566,10 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; * declared instance of @t. */ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +/** true when value is odd integer */ +#define isIntOdd(value) (value&1) +/** true when value is even integer */ +#define isIntEven(value) (!(value&1)) /* * typ definition as alternative to typedef */ @@ -16024,6 +16053,7 @@ toUnsignedType(var) convertToUnsignedType(var) castS(casted, toCast) _ +BSLH ssGet(obj) sjGet(obj) replaceSO_max(obj,olds,news) @@ -16376,6 +16406,7 @@ aLoad(obj) aCompareExchangeStrong(obj, expected, desired) aFetchAdd(obj, valueToAdd) aFetchSub(obj, valueToSub) +#if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4) aStaticArrayT(typeName, element, MAXCOUNT) aStaticArrayInit(name) aStaticArrayAcquire(name) @@ -17209,6 +17240,7 @@ bool areAllEBytes (smallArrayt *self); Class SmallJson +enum {KEY_IS_NULL=0, NOT_A_PATH, ARRAY_PATH, DICT_PATH} jsonPathRest; void free (smallJsont *self); void terminate (smallJsont **self); char* toString (smallJsont *self); @@ -17281,6 +17313,13 @@ smallBoolt* getTopSmallBool (smallJsont *self); smallDoublet* getTopSmallDouble(smallJsont *self); smallIntt* getTopSmallInt (smallJsont *self); smallStringt* getTopSmallString(smallJsont *self); +jsonPathRest keyIs (smallJsont *self, const char *key); +const char* keyIsS (smallJsont *self, const char *key); +char* makeKey (smallJsont *self, const char *key); +char* iMakeKey (smallJsont *self, char **key); +char* bMakeKey (smallJsont *self, char *dest, const char *key); +char* bLMakeKey (smallJsont *self, char *dest, size_t size, const char *key); +size_t makeKeyLen(smallJsont *self, const char *key); smallJsont* set (smallJsont *self, const char *key, baset *value); smallJsont* setUndefined(smallJsont *self, const char *key); smallJsont* setBool (smallJsont *self, const char *key, bool value); @@ -52058,11 +52097,7 @@ smallDoublet* duplicateSmallDoubleG (smallDoublet *self); */ smallIntt* duplicateSmallInt (smallIntt *self); smallIntt* duplicateSmallIntG (smallIntt *self); -/* - * help text for this class - * It is public declaration so that child classes can add their help text easily: - * ret "Child help text \n\n" helpTextSmallJson; - */ +/* array to convert jsonPathRest to string */ smallJsont* duplicateSmallJson (smallJsont *self); smallJsont* duplicateSmallJsonG (smallJsont *self); /* @@ -52870,14 +52905,14 @@ void disposeSmallDict (smallDictt *self); * self becomes empty. * * Useful when the objects are shared - */ + */ void disposeSmallJson (smallJsont *self); /* * free index but not the elements * self becomes empty. * * Useful when the objects are shared - */ + */ void disposeSmallJson (smallJsont *self); #define helpO(self) (self)->f->help(self) #define helpG helpO @@ -71505,6 +71540,8 @@ smallStringt* insertNFreeSmallString (smallStringt *self, intmax_t index, smallS * "\"a\".\"bsd\"" */ #define _ "\"" +/** Back Slash string to escape back slash, use in for example json path with get, set... */ +#define BSLH "\\" /* * get a pointer to the string in the smallString object * @@ -72748,6 +72785,7 @@ baset *toBaset(smallt *obj); /* * base type for atomic staticArrays */ +#if (!__OpenBSD__) && ! defined(__TINYC__) && (__GNUC__ > 4) /* * declares type for atomic staticArray * diff --git a/release/json/libsheepyCSmallJson.h b/release/json/libsheepyCSmallJson.h @@ -50,6 +50,15 @@ typedef struct smallJson smallJsont; // for object inheriting smallJson, cast to smallJson to be able to use this class functions and generics #define cJs(self) ( (smallJsont*) self ) +/** json Path Result + * enum type for key type + * NOT_A_PATH is a dictionary key + */ +typedef enum {KEY_IS_NULL=0, NOT_A_PATH, ARRAY_PATH, DICT_PATH} jsonPathRest; + +/** array to convert jsonPathRest to string */ +extern const char *jsonPathResS[]; + typedef void (*freeSmallJsonFt) (smallJsont *self); typedef void (*terminateSmallJsonFt) (smallJsont **self); typedef char* (*toStringSmallJsonFt) (smallJsont *self); @@ -60,7 +69,7 @@ typedef smallJsont* (*duplicateSmallJsonFt) (smallJsont *self); * self becomes empty. * * Useful when the objects are shared - */ + */ typedef void (*disposeSmallJsonFt) (smallJsont *self); /** @@ -239,6 +248,99 @@ typedef smallIntt* (*getTopSmallIntSmallJsonFt) (smallJsont *self); typedef smallStringt* (*getTopSmallStringSmallJsonFt)(smallJsont *self); /** + * keyIs + * determine json key type: dictionary key, json path starting from an array or json path starting from a dictionary + * + * use the jsonPathResS[] array to convert the result to string (or use keyIsS to get the result as string directly) + * + * \param + * key any key or path in self + * \return + * key type (enum int) + * 0 (KEY_IS_NULL in enum) when key is NULL + */ +typedef jsonPathRest (*keyIsSmallJsonFt) (smallJsont *self, const char *key); + +/** + * keyIs returning result as string + * determine json key type: dictionary key, json path starting from an array or json path starting from a dictionary + * + * \param + * key any key or path in self + * \return + * key type + * NULL when key is NULL + */ +typedef const char* (*keyIsSSmallJsonFt) (smallJsont *self, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * + * \param + * key key to transform + * \return + * new dictionary key (you must free this buffer) + * NULL when key is NULL + */ +typedef char* (*makeKeySmallJsonFt) (smallJsont *self, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * + * \param + * key pointer to key to transform (this parameter is reallocated) + * \return + * new dictionary key (you must free this buffer) + * NULL when key is NULL + */ +typedef char* (*iMakeKeySmallJsonFt) (smallJsont *self, char **key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * the result is stored dest, dest must be big enough (at least makeKeyLen+1) + * + * \param + * key key to transform + * \param + * dest result buffer + * \return + * dictionary key in dest + * NULL when key is NULL + */ +typedef char* (*bMakeKeySmallJsonFt) (smallJsont *self, char *dest, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * the result is stored dest, dest size must be big enough (at least makeKeyLen+1) + * + * \param + * key key to transform + * \param + * dest result buffer + * \param + * size dest buffer size + * \return + * dictionary key in dest + * NULL when key is NULL + */ +typedef char* (*bLMakeKeySmallJsonFt) (smallJsont *self, char *dest, size_t size, const char *key); + +/** + * return key length after running makeKey + * + * \param + * key key to transform + * \return + * dictionary key length + * 0 when key is NULL + */ +typedef size_t (*makeKeyLenSmallJsonFt)(smallJsont *self, const char *key); + +/** * set element * * When the sObject pointer is updated by realloc, the sObject @@ -2402,6 +2504,13 @@ typedef bool (*areAllEBytesSmallJsonFt) (smallJsont *self); getTopSmallDoubleSmallJsonFt getTopSmallDouble;\ getTopSmallIntSmallJsonFt getTopSmallInt;\ getTopSmallStringSmallJsonFt getTopSmallString;\ + keyIsSmallJsonFt keyIs;\ + keyIsSSmallJsonFt keyIsS;\ + makeKeySmallJsonFt makeKey;\ + iMakeKeySmallJsonFt iMakeKey;\ + bMakeKeySmallJsonFt bMakeKey;\ + bLMakeKeySmallJsonFt bLMakeKey;\ + makeKeyLenSmallJsonFt makeKeyLen;\ setSmallJsonFt set;\ setUndefinedSmallJsonFt setUndefined;\ setBoolSmallJsonFt setBool;\ diff --git a/release/libsheepy.c b/release/libsheepy.c @@ -54015,10 +54015,10 @@ void scheduler(void) { +#if ((__GNUC__ > 4)) /** * return monotonic time in nanoseconds */ -#if ((__GNUC__ > 4)) uint64_t getMonotonicTime(void) { struct timespec ts; diff --git a/release/libsheepy.h b/release/libsheepy.h @@ -96,7 +96,7 @@ // version accoring to the version package: Release.Major.minor.patch // https://noulin.net/version/file/README.md.html -#define LIBSHEEPY_VERSION "1.0.5.1" +#define LIBSHEEPY_VERSION "1.0.6" #ifndef SH_PREFIX #define SH_PREFIX(NAME) NAME @@ -301,6 +301,20 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; #define f32 float #define f64 double +/** + * type cast + */ +#define I8(value) (i8)(value) +#define I16(value) (i16)(value) +#define I32(value) (i32)(value) +#define I64(value) (i64)(value) +#define U8(value) (u8)(value) +#define U16(value) (u16)(value) +#define U32(value) (u32)(value) +#define U64(value) (u64)(value) +#define F32(value) (f32)(value) +#define F64(value) (f64)(value) + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN3(a, b, c) MIN((typeof(a))MIN(a, b), c) @@ -401,6 +415,12 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; */ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +/** true when value is odd integer */ +#define isIntOdd(value) (value&1) + +/** true when value is even integer */ +#define isIntEven(value) (!(value&1)) + /** * typ definition as alternative to typedef */ diff --git a/release/libsheepyObject.h b/release/libsheepyObject.h @@ -8349,6 +8349,9 @@ void finishManyOF(void *paramType, ...); */ typedef struct base baset; +// for object inheriting baset, cast to baset to be able to use this class functions and generics +#define cBa(self) ( (baset*) self ) + // Functions /** @@ -8551,6 +8554,9 @@ extern smallContainert* rtSmallContainert; */ #define _ "\"" +/** Back Slash string to escape back slash, use in for example json path with get, set... */ +#define BSLH "\\" + /** * get a pointer to the string in the smallString object * diff --git a/src/json/libsheepyCSmallJson.c b/src/json/libsheepyCSmallJson.c @@ -123,6 +123,15 @@ internal smallBoolt* getTopSmallBoolSmallJson(smallJsont *self); internal smallDoublet* getTopSmallDoubleSmallJson(smallJsont *self); internal smallIntt* getTopSmallIntSmallJson(smallJsont *self); internal smallStringt* getTopSmallStringSmallJson(smallJsont *self); +internal bool isPythonIndex(const char *start, size_t len); +internal jsonPathRest keyIsSmallJson(smallJsont *self UNUSED, const char *key); +internal const char* keyIsSSmallJson(smallJsont *self UNUSED, const char *key); +internal char* makeKeySmallJson(smallJsont *self UNUSED, const char *key); +internal char* iMakeKeySmallJson(smallJsont *self UNUSED, char **key); +internal char* bMakeKeySmallJson(smallJsont *self UNUSED, char *dest, const char *key); +internal char* bLMakeKeySmallJson(smallJsont *self UNUSED, char *dest, size_t size, const char *key); +internal size_t makeKeyLenSmallJson(smallJsont *self UNUSED, const char *key); +internal void unescapeKey(char *dest, char *key, size_t length); internal smallJsont* setSmallJson(smallJsont *self, const char *key, baset *value); internal smallJsont* setUndefinedSmallJson(smallJsont *self, const char *key); internal smallJsont* setBoolSmallJson(smallJsont *self, const char *key, bool value); @@ -1571,6 +1580,8 @@ bool appendTextJsonSmallJsonG(smallJsont *self, smallJsont *filePath); enum {SMALLJSON_IS_EMPTY, TOP_IS_UNDEFINED, TOP_IS_BOOL, TOP_IS_DOUBLE, TOP_IS_INT, TOP_IS_STRING, TOP_IS_DICT, TOP_IS_ARRAY}; +const char *jsonPathResS[] = {"KEY_IS_NULL", "NOT_A_PATH", "ARRAY_PATH", "DICT_PATH", NULL}; + #define eprintf shEPrintfS void initiateSmallJson(smallJsont *self) { @@ -1670,6 +1681,13 @@ void registerMethodsSmallJson(smallJsonFunctionst *f) { f->getTopSmallDouble = getTopSmallDoubleSmallJson; f->getTopSmallInt = getTopSmallIntSmallJson; f->getTopSmallString = getTopSmallStringSmallJson; + f->keyIs = keyIsSmallJson; + f->keyIsS = keyIsSSmallJson; + f->makeKey = makeKeySmallJson; + f->iMakeKey = iMakeKeySmallJson; + f->bMakeKey = bMakeKeySmallJson; + f->bLMakeKey = bLMakeKeySmallJson; + f->makeKeyLen = makeKeyLenSmallJson; f->set = setSmallJson; f->setUndefined = setUndefinedSmallJson; f->setBool = setBoolSmallJson; @@ -3516,1034 +3534,541 @@ internal smallStringt* getTopSmallStringSmallJson(smallJsont *self) { } -internal smallJsont* setSmallJson(smallJsont *self, const char *key, baset *value) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } +internal bool isPythonIndex(const char *start, size_t len) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - if (!value) { - o = (smallt *)allocSUndefined(); - } - else { - o = toSmallt(value); - } - setJsonPath; - break; - } - return(self); + char s[len+1]; + memcpy(s, start, len); + s[len] = 0; + return(isInt(s)); } -internal smallJsont* setUndefinedSmallJson(smallJsont *self, const char *key) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal jsonPathRest keyIsSmallJson(smallJsont *self UNUSED, const char *key) { if (!key) { - return(NULL); - } + return(KEY_IS_NULL); + } + + /* detect if key is a dict key or a path */ + /* path must start with " or [ */ + /* the chars between [ and ] must be integers */ + /* key chars must be surrounded with " */ + /* invalid path are dict keys */ + /* escape \" \\ */ + + jsonPathRest keyIs = NOT_A_PATH; + + enum {SEARCH, IN_STRING, IN_INDEX}; + int state = SEARCH; + + if (key[0]=='"' || key[0]=='[') { + /* path must start with " or [ */ + bool escape = false; + const char *start = NULL; + size_t startIdx = 0; + for (size_t i = 0 ; key[i] ; i++) { + if (escape) { + escape = false; + continue; + } + + switch (key[i]) { + case '"': + /* key chars must be surrounded with " */ + switch(state) { + case SEARCH: + state = IN_STRING; + break; + case IN_STRING: + state = SEARCH; + break; + default: + goto endKeyParse; + } + break; + case '[': + switch(state) { + case SEARCH: + state = IN_INDEX; + start = &key[i+1]; + startIdx = i+1; + break; + case IN_INDEX: + /* 2 [ following each other, not a path */ + goto endKeyParse; + } + break; + case ']': + switch(state) { + case IN_INDEX: + state = SEARCH; + /* check if there is an int between the [] */ + if (!isPythonIndex(start, i-startIdx)) { + goto endKeyParse; + } + break; + case SEARCH: + /* missing [, not a path */ + goto endKeyParse; + } + break; + default: + switch(state) { + case SEARCH: + if (key[i]!='.') { + goto endKeyParse; + } + break; + case IN_INDEX: + /* the chars between [ and ] must be integers */ + if (!isdigit(key[i]) && key[i]!=']' && key[i]!='-') { + goto endKeyParse; + } + break; + case IN_STRING: + /* escape \" \\ */ + if (key[i]=='\\') { + escape = true; + } + break; + } + break; + } + } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - o = (smallt *) allocSUndefined(); - setJsonPath; - break; + if (state==SEARCH) { + /* all path elements must be closed */ + switch(key[0]) { + case '"': + keyIs = DICT_PATH; + break; + case '[': + keyIs = ARRAY_PATH; + break; + } } - return(self); -} + } -internal smallJsont* setBoolSmallJson(smallJsont *self, const char *key, bool value) { - smallt *o = NULL; + endKeyParse: + return(keyIs); +} - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal const char* keyIsSSmallJson(smallJsont *self UNUSED, const char *key) { if (!key) { return(NULL); } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - o = (smallt *) allocSBool(value); - setJsonPath; - break; - } - return(self); -} + jsonPathRest keyIs = keyIsSmallJson(self, key); -internal smallJsont* setDoubleSmallJson(smallJsont *self, const char *key, double value) { - smallt *o = NULL; + return(jsonPathResS[keyIs]); +} - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal char* makeKeySmallJson(smallJsont *self UNUSED, const char *key) { if (!key) { return(NULL); } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - o = (smallt *) allocSDouble(value); - setJsonPath; - break; - } - return(self); -} - -internal smallJsont* setIntSmallJson(smallJsont *self, const char *key, int64_t value) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + char *r = strdup(_); - if (!key) { - return(NULL); + for (size_t i = 0 ; key[i] ; i++) { + if (key[i]=='"' || key[i]=='\\') { + iAppendS(&r, BSLH); + } + iAppendCharS(&r, key[i]); } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - o = (smallt *) allocSInt(value); - setJsonPath; - break; - } - return(self); + // close quote + iAppendS(&r, _); + return(r); } -internal smallJsont* setSSmallJson(smallJsont *self, const char *key, const char *string) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal char* iMakeKeySmallJson(smallJsont *self UNUSED, char **key) { - if (!key) { + if (!key && !*key) { return(NULL); } - if (!string) { - // set empty string when NULL - o = (smallt *) allocSStringTiny(""); - } - else { - o = (smallt *) allocSStringTiny(string); - } - - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + char *r = makeKeySmallJson(self, *key); + free(*key); + *key = r; + return(r); } -internal smallJsont* setCharSmallJson(smallJsont *self, const char *key, char c) { +internal char* bMakeKeySmallJson(smallJsont *self UNUSED, char *dest, const char *key) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { + if (!key || !dest) { return(NULL); } - if (!key) { - return(NULL); + size_t di = 0; + dest[di++] = '"'; + + for (size_t i = 0 ; key[i] ; i++) { + if (key[i]=='"' || key[i]=='\\') { + dest[di++] = '\\'; + } + dest[di++] = key[i]; } - charToS(s, c); - return(setSSmallJson(self, key, s)); + // close quote + dest[di++] = '"'; + dest[di] = 0; + return(dest); } -internal smallJsont* setDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - smallt *o = NULL; +internal char* bLMakeKeySmallJson(smallJsont *self UNUSED, char *dest, size_t size, const char *key) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { + if (!key || !dest || !size) { return(NULL); } - if (!key) { + if (makeKeyLenSmallJson(self, key)+1 > size) { return(NULL); } - if (checkObjectTypes && dict && !isOSmallDict(dict)) { + size_t di = 0; + dest[di++] = '"'; + if (di >= size) { return(NULL); } - if (!dict) { - o = (smallt *) allocSDict(); - } - else { - if (!dict->d) { - dict->d = allocSDict(); + for (size_t i = 0 ; key[i] ; i++) { + if (key[i]=='"' || key[i]=='\\') { + dest[di++] = '\\'; + if (di >= size) { + return(NULL); } - o = (smallt *)dict->d; + } + dest[di++] = key[i];; + if (di >= size) { + return(NULL); } + } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; + // close quote + dest[di++] = '"'; + if (di >= size) { + return(NULL); } - return(self); + dest[di] = 0; + return(dest); } -internal smallJsont* setArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal size_t makeKeyLenSmallJson(smallJsont *self UNUSED, const char *key) { if (!key) { - return(NULL); + return(0); } - if (checkObjectTypes && array && !isOSmallArray(array)) { - return(NULL); - } + size_t r = 1; - if (!array) { - o = (smallt *) allocSArray(); - } - else { - if (!array->a) { - // allocate empty array - array->a = allocSArray(); + for (size_t i = 0 ; key[i] ; i++) { + if (key[i]=='"' || key[i]=='\\') { + r++; } - o = (smallt *)array->a; + r++; } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + // close quote + r++; + return(r); } -internal smallJsont* setArraycSmallJson(smallJsont *self, const char *key, char **array) { - smallt *o = NULL; +internal void unescapeKey(char *dest, char *key, size_t length) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + bool skipped = false; + size_t j = 0; + range(i, length) { + if (skipped) { + skipped = false; + if (key[i-1] == '\\') { + goto keepBackSlash; + } + } + if (key[i] == '\\' && !skipped) { + skipped = true; + } + keepBackSlash: + if (!skipped) { + dest[j++] = key[i]; + } } + dest[j] = 0; +} - if (!key) { - return(NULL); - } - if (!array) { - o = (smallt *) allocSArray(); - } - else { - sArrayt *a = allocSArray(); - forEachCharP(array, e) { - sStringt *s = allocSStringTiny(*e); - sArrayPushTiny(&a, (smallt *) s); - } - o = (smallt *)a; - } +internal smallJsont* setSmallJson(smallJsont *self, const char *key, baset *value) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(/*initValue*/, o=!value?(smallt*)allocSUndefined():toSmallt(value)/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } -internal smallJsont* setSmallBoolSmallJson(smallJsont *self, const char *key, smallBoolt *value) { - smallt *o = NULL; +internal smallJsont* setUndefinedSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + mainSetJsonPath(/*initValue*/, o=(smallt*)allocSUndefined()/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!key) { - return(NULL); - } +internal smallJsont* setBoolSmallJson(smallJsont *self, const char *key, bool value) { - if (checkObjectTypes && value && !isOSmallBool(value)) { - return(NULL); - } + mainSetJsonPath(/*initValue*/, o=(smallt*)allocSBool(value)/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - o = (smallt *) value->value; - } +internal smallJsont* setDoubleSmallJson(smallJsont *self, const char *key, double value) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(/*initValue*/, o=(smallt*)allocSDouble(value)/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } -internal smallJsont* setSmallBytesSmallJson(smallJsont *self, const char *key, smallBytest *value) { - smallt *o = NULL; +internal smallJsont* setIntSmallJson(smallJsont *self, const char *key, int64_t value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + mainSetJsonPath(/*initValue*/, o=(smallt*)allocSInt(value)/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!key) { - return(NULL); - } +internal smallJsont* setSSmallJson(smallJsont *self, const char *key, const char *string) { - if (checkObjectTypes && value && !isOSmallBytes(value)) { - return(NULL); - } + mainSetJsonPath(o=!string?/*set empty string when NULL*/(smallt*)allocSStringTiny(""):(smallt*)allocSStringTiny(string)/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!value || !value->B) { - o = (smallt *) allocSUndefined(); - } - else { - o = (smallt *) value->B; - } +internal smallJsont* setCharSmallJson(smallJsont *self, const char *key, char c) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + charToS(s, c); + return(setSSmallJson(self, key, s)); } -internal smallJsont* setSmallDoubleSmallJson(smallJsont *self, const char *key, smallDoublet *value) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } +internal smallJsont* setDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - if (checkObjectTypes && value && !isOSmallDouble(value)) { - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && dict && !isOSmallDict(dict)) return NULL;if (!dict) o = (smallt *) allocSDict(); else{if (!dict->d) dict->d = allocSDict();o = (smallt *)dict->d;}/*initValue*/,/*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - o = (smallt *) value->value; - } +internal smallJsont* setArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(if (checkObjectTypes && array && !isOSmallArray(array)) return NULL; if (!array) o = (smallt *) allocSArray(); else {if (!array->a) /*allocate empty array*/ array->a = allocSArray(); o = (smallt *)array->a;}/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } -internal smallJsont* setSmallIntSmallJson(smallJsont *self, const char *key, smallIntt *value) { - smallt *o = NULL; +internal smallJsont* setArraycSmallJson(smallJsont *self, const char *key, char **array) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + mainSetJsonPath(if (!array) o = (smallt *) allocSArray(); else {sArrayt *a = allocSArray();forEachCharP(array, e){sStringt *s = allocSStringTiny(*e);sArrayPushTiny(&a, (smallt *) s);}o = (smallt *)a;}/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!key) { - return(NULL); - } +internal smallJsont* setSmallBoolSmallJson(smallJsont *self, const char *key, smallBoolt *value) { - if (checkObjectTypes && value && !isOSmallInt(value)) { - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallBool(value)) return NULL; o = !value?(smallt*)allocSUndefined():(smallt*)value->value/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - o = (smallt *) value->value; - } +internal smallJsont* setSmallBytesSmallJson(smallJsont *self, const char *key, smallBytest *value) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallBytes(value)) return NULL; o = (!value||!value->B)?(smallt*)allocSUndefined():(smallt*)value->B/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } -internal smallJsont* setSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } +internal smallJsont* setSmallDoubleSmallJson(smallJsont *self, const char *key, smallDoublet *value) { - if (!key) { - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallDouble(value)) return NULL; o = !value?(smallt*)allocSUndefined():(smallt*)value->value/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - if (checkObjectTypes && value && !isOSmallJson(value)) { - return(NULL); - } +internal smallJsont* setSmallIntSmallJson(smallJsont *self, const char *key, smallIntt *value) { - smallt *o; - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - switch(value->topIsA){ - case SMALLJSON_IS_EMPTY: - o = (smallt *) allocSUndefined(); - break; - case TOP_IS_UNDEFINED: - o = (smallt *) value->topU; - break; - case TOP_IS_BOOL: - o = (smallt *) value->topB; - break; - case TOP_IS_DOUBLE: - o = (smallt *) value->topD; - break; - case TOP_IS_INT: - o = (smallt *) value->topI; - break; - case TOP_IS_STRING: - o = (smallt *) value->topS; - break; - case TOP_IS_DICT: - o = (smallt *) value->top; - break; - case TOP_IS_ARRAY: - o = (smallt *) value->topA; - break; - } - } + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallInt(value)) return NULL; o = !value?(smallt*)allocSUndefined():(smallt*)value->value/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug +} - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } +internal smallJsont* setSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - return(self); + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallJson(value)) return NULL; if (!value) o = (smallt *) allocSUndefined(); else {switch(value->topIsA){case SMALLJSON_IS_EMPTY:o = (smallt *) allocSUndefined();break;case TOP_IS_UNDEFINED:o = (smallt *) value->topU;break;case TOP_IS_BOOL:o = (smallt *) value->topB;break;case TOP_IS_DOUBLE:o = (smallt *) value->topD;break;case TOP_IS_INT:o = (smallt *) value->topI;break;case TOP_IS_STRING:o = (smallt *) value->topS;break;case TOP_IS_DICT:o = (smallt *) value->top;break;case TOP_IS_ARRAY:o = (smallt *) value->topA;break;}}/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } internal smallJsont* setSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && string && !isOSmallString(string)) { - return(NULL); - } - - if (!string || !string->data) { - o = (smallt *) allocSStringTiny(""); - } - else { - o = (smallt *) string->data; - } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(if (checkObjectTypes && string && !isOSmallString(string)) return NULL; o = (!string||!string->data)?(smallt*)allocSUndefined():(smallt*)string->data/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } internal smallJsont* setSmallContainerSmallJson(smallJsont *self, const char *key, smallContainert *container) { - smallt *o = NULL; - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && container && !isOSmallContainer(container)) { - return(NULL); - } - - if (!container) { - o = (smallt *) allocSUndefined(); - } - else { - if (!container->data) { - o = (smallt *) allocSContainer(NULL); - } - else { - o = (smallt *) container->data; - } - } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setJsonPath; - break; - } - return(self); + mainSetJsonPath(if (checkObjectTypes && container && !isOSmallContainer(container)) return NULL; if (!container) o = (smallt *) allocSUndefined(); else {if (!container->data) o = (smallt *) allocSContainer(NULL); else o = (smallt *) container->data;}/*initValue*/, /*allocValue*/, setJsonPath/*subSetJsonPath*/); + // cg_c bug } internal smallJsont* setNFreeSmallJson(smallJsont *self, const char *key, baset *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + smallJsont *r = setSmallJson(self, key, value); + if (r) { + /* free parameter only when successfully stored in self */ + finishO(value); } - - setSmallJson(self, key, value); - finishO(value); return(self); } internal smallJsont* setNFreeUndefinedSmallJson(smallJsont *self, const char *key, undefinedt *undefined) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + smallJsont *r = setUndefinedSmallJson(self, key); + if (r) { + /* free parameter only when successfully stored in self */ + terminateO(undefined); } - - setUndefinedSmallJson(self, key); - terminateO(undefined); return(self); } internal smallJsont* setNFreeSSmallJson(smallJsont *self, const char *key, char *string) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + smallJsont *r = setSSmallJson(self, key, string); + if (r) { + /* free parameter only when successfully stored in self */ + free(string); } - - setSSmallJson(self, key, string); - free(string); return(self); } internal smallJsont* setNFreeDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - smallJsont *r = setDictSmallJson(self, key, dict); if (r) { + /* free parameter only when successfully stored in self */ finishO(dict); } - else { - terminateO(dict); - } return(r); } internal smallJsont* setNFreeArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - smallJsont *r = setArraySmallJson(self, key, array); if (r) { + /* free parameter only when successfully stored in self */ finishO(array); } - else { - terminateO(array); - } return(r); } internal smallJsont* setNFreeArraycSmallJson(smallJsont *self, const char *key, char **array) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + smallJsont *r = setArraycSmallJson(self, key, array); + if (r) { + listFreeS(array); } - - setArraycSmallJson(self, key, array); - listFreeS(array); return(self); } internal smallJsont* setNFreeSmallBoolSmallJson(smallJsont *self, const char *key, smallBoolt *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - smallJsont *r = setSmallBoolSmallJson(self, key, value); if (r) { finishO(value); } - else { - terminateO(value); - } return(r); } internal smallJsont* setNFreeSmallBytesSmallJson(smallJsont *self, const char *key, smallBytest *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - smallJsont *r = setSmallBytesSmallJson(self, key, value); if (r) { finishO(value); } - else { - terminateO(value); - } return(r); } internal smallJsont* setNFreeSmallDoubleSmallJson(smallJsont *self, const char *key, smallDoublet *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - smallJsont *r = setSmallDoubleSmallJson(self, key, value); if (r) { finishO(value); } - else { - terminateO(value); - } return(r); } internal smallJsont* setNFreeSmallIntSmallJson(smallJsont *self, const char *key, smallIntt *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - smallJsont *r = setSmallIntSmallJson(self, key, value); - if (r) { - finishO(value); - } - else { - terminateO(value); - } - return(r); -} - -internal smallJsont* setNFreeSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - smallJsont *r = setSmallJsonSmallJson(self, key, value); - if (r) { - finishO(value); - } - else { - terminateO(value); - } - return(r); -} - -internal smallJsont* setNFreeSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - smallJsont *r = setSmallStringSmallJson(self, key, string); - if (r) { - finishO(string); - } - else { - terminateO(string); - } - return(r); -} - -internal smallJsont* setNFreeSmallContainerSmallJson(smallJsont *self, const char *key, smallContainert *container) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - smallJsont *r = setSmallContainerSmallJson(self, key, container); - if (r) { - finishO(container); - } - else { - terminateO(container); - } - return(r); -} - -internal smallJsont* setPDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && dict && !isOSmallDict(dict)) { - return(NULL); - } - - if (!dict) { - sDictSetP(&(self->top), key, (smallt *)allocSDict()); - return(self); - } - - if (!dict->d) { - dict->d = allocSDict();; - } - - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPJsonPath((smallt *)dict->d); - break; - } - return(self); -} - -internal smallJsont* setPArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && !isOSmallArray(array)) { - return(NULL); - } - - if (!array) { - sDictSetP(&(self->top), key, (smallt *)allocSArray()); - return(self); - } - - if (!array->a) { - // allocate empty array - array->a = allocSArray(); - } - - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPJsonPath((smallt *)array->a); - break; - } - return(self); -} - -internal smallJsont* setPSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && value && !isOSmallJson(value)) { - return(NULL); - } - - smallt *o; - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - switch(value->topIsA){ - case SMALLJSON_IS_EMPTY: - o = (smallt *) allocSUndefined(); - break; - case TOP_IS_UNDEFINED: - o = (smallt *) value->topU; - break; - case TOP_IS_BOOL: - o = (smallt *) value->topB; - break; - case TOP_IS_DOUBLE: - o = (smallt *) value->topD; - break; - case TOP_IS_INT: - o = (smallt *) value->topI; - break; - case TOP_IS_STRING: - o = (smallt *) value->topS; - break; - case TOP_IS_DICT: - o = (smallt *) value->top; - break; - case TOP_IS_ARRAY: - o = (smallt *) value->topA; - break; - } - } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPJsonPath(o); - break; - } - return(self); -} - -internal smallJsont* setPSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - return(NULL); - } - - if (checkObjectTypes && string && !isOSmallString(string)) { - return(NULL); - } - - smallt *o; - if (!string || !string->data) { - // set empty string when NULL - o = (smallt *) allocSStringTiny(""); - } - else { - o = (smallt *) string->data; - } - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPJsonPath(o); - break; - } - return(self); -} - -internal smallJsont* setNFreePDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } - - if (!key) { - terminateO(dict); - return(NULL); - } - - if (checkObjectTypes && dict && !isOSmallDict(dict)) { - terminateO(dict); - return(NULL); - } - - if (!dict) { - sDictSetP(&(self->top), key, (smallt *)allocSDict()); - return(self); - } - - if (!dict->d) { - dict->d = allocSDict();; - } - - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPNFreeJsonPath((smallt *)dict->d, finishO(dict)); - break; - } - finishO(dict); - return(self); + smallJsont *r = setSmallIntSmallJson(self, key, value); + if (r) { + finishO(value); + } + return(r); } -internal smallJsont* setNFreePArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { +internal smallJsont* setNFreeSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); + smallJsont *r = setSmallJsonSmallJson(self, key, value); + if (r) { + finishO(value); } + return(r); +} - if (!key) { - terminateO(array); - return(NULL); - } +internal smallJsont* setNFreeSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { - if (checkObjectTypes && array && !isOSmallArray(array)) { - terminateO(array); - return(NULL); + smallJsont *r = setSmallStringSmallJson(self, key, string); + if (r) { + finishO(string); } + return(r); +} - if (!array) { - sDictSetP(&(self->top), key, (smallt *)allocSArray()); - return(self); - } +internal smallJsont* setNFreeSmallContainerSmallJson(smallJsont *self, const char *key, smallContainert *container) { - if (!array->a) { - // allocate empty array - array->a = allocSArray(); + smallJsont *r = setSmallContainerSmallJson(self, key, container); + if (r) { + finishO(container); } - - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPNFreeJsonPath((smallt *)array->a, finishO(array)); - break; - } - return(self); + return(r); } -internal smallJsont* setNFreePSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { +internal smallJsont* setPDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && dict && !isOSmallDict(dict)) return NULL;if (!dict) o = (smallt *) allocSDict(); else o = (smallt *)dict->d/*initValue*/,/*allocValue*/, setPJsonPath(o)/*subSetJsonPath*/); + // cg_c bug +} - if (!key) { - terminateO(value); - return(NULL); - } +internal smallJsont* setPArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - if (checkObjectTypes && value && !isOSmallJson(value)) { - terminateO(value); - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && array && !isOSmallArray(array)) return NULL; if (!array) o = (smallt *) allocSArray(); else o = (smallt *)array->a/*initValue*/, /*allocValue*/, setPJsonPath(o)/*subSetJsonPath*/); + // cg_c bug +} - smallt *o; - if (!value) { - o = (smallt *) allocSUndefined(); - } - else { - switch(value->topIsA){ - case SMALLJSON_IS_EMPTY: - o = (smallt *) allocSUndefined(); - break; - case TOP_IS_UNDEFINED: - o = (smallt *) value->topU; - break; - case TOP_IS_BOOL: - o = (smallt *) value->topB; - break; - case TOP_IS_DOUBLE: - o = (smallt *) value->topD; - break; - case TOP_IS_INT: - o = (smallt *) value->topI; - break; - case TOP_IS_STRING: - o = (smallt *) value->topS; - break; - case TOP_IS_DICT: - o = (smallt *) value->top; - break; - case TOP_IS_ARRAY: - o = (smallt *) value->topA; - break; - } - } +internal smallJsont* setPSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPNFreeJsonPath(o, finishO(value)); - break; - } - finishO(value); - return(self); + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallJson(value)) return NULL; if (!value) o = (smallt *) allocSUndefined(); else {switch(value->topIsA){case SMALLJSON_IS_EMPTY:o = (smallt *) allocSUndefined();break;case TOP_IS_UNDEFINED:o = (smallt *) value->topU;break;case TOP_IS_BOOL:o = (smallt *) value->topB;break;case TOP_IS_DOUBLE:o = (smallt *) value->topD;break;case TOP_IS_INT:o = (smallt *) value->topI;break;case TOP_IS_STRING:o = (smallt *) value->topS;break;case TOP_IS_DICT:o = (smallt *) value->top;break;case TOP_IS_ARRAY:o = (smallt *) value->topA;break;}}/*initValue*/, /*allocValue*/, setPJsonPath(o)/*subSetJsonPath*/); + // cg_c bug } -internal smallJsont* setNFreePSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { +internal smallJsont* setPSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { - if (self->topIsA != SMALLJSON_IS_EMPTY && self->topIsA != TOP_IS_DICT) { - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && string && !isOSmallString(string)) return NULL; o = (!string||!string->data)?(smallt*)allocSUndefined():(smallt*)string->data/*initValue*/, /*allocValue*/, setPJsonPath(o)/*subSetJsonPath*/); + // cg_c bug +} - if (!key) { - terminateO(string); - return(NULL); - } +internal smallJsont* setNFreePDictSmallJson(smallJsont *self, const char *key, smallDictt *dict) { - if (checkObjectTypes && string && !isOSmallString(string)) { - terminateO(string); - return(NULL); - } + mainSetJsonPath(if (checkObjectTypes && dict && !isOSmallDict(dict)) return NULL;if (!dict) o = (smallt *) allocSDict(); else o = (smallt *)dict->d/*initValue*/,/*allocValue*/, setPNFreeJsonPath(o,finishO(dict));finishO(dict)/*subSetJsonPath*/); + // cg_c bug +} - if (!string) { - sDictSetP(&(self->top), key, (smallt *)allocSStringTiny("")); - return(self); - } +internal smallJsont* setNFreePArraySmallJson(smallJsont *self, const char *key, smallArrayt *array) { - if (!string->data) { - string->data = allocSStringTiny(""); - } + mainSetJsonPath(if (checkObjectTypes && array && !isOSmallArray(array)) return NULL; if (!array) o = (smallt *) allocSArray(); else o = (smallt *)array->a/*initValue*/, /*allocValue*/, setPNFreeJsonPath(o,finishO(array));finishO(array)/*subSetJsonPath*/); + // cg_c bug +} - switch(self->topIsA) { - case SMALLJSON_IS_EMPTY: - self->topIsA = TOP_IS_DICT; - case TOP_IS_DICT: - setPNFreeJsonPath((smallt *)string->data, finishO(string)); - break; - } - finishO(string); - return(self); +internal smallJsont* setNFreePSmallJsonSmallJson(smallJsont *self, const char *key, smallJsont *value) { + + mainSetJsonPath(if (checkObjectTypes && value && !isOSmallJson(value)) return NULL; if (!value) o = (smallt *) allocSUndefined(); else {switch(value->topIsA){case SMALLJSON_IS_EMPTY:o = (smallt *) allocSUndefined();break;case TOP_IS_UNDEFINED:o = (smallt *) value->topU;break;case TOP_IS_BOOL:o = (smallt *) value->topB;break;case TOP_IS_DOUBLE:o = (smallt *) value->topD;break;case TOP_IS_INT:o = (smallt *) value->topI;break;case TOP_IS_STRING:o = (smallt *) value->topS;break;case TOP_IS_DICT:o = (smallt *) value->top;break;case TOP_IS_ARRAY:o = (smallt *) value->topA;break;}}/*initValue*/, /*allocValue*/, setPNFreeJsonPath(o,finishO(value));finishO(value)/*subSetJsonPath*/); + // cg_c bug } +internal smallJsont* setNFreePSmallStringSmallJson(smallJsont *self, const char *key, smallStringt *string) { + + mainSetJsonPath(if (checkObjectTypes && string && !isOSmallString(string)) return NULL; o = (!string||!string->data)?(smallt*)allocSUndefined():(smallt*)string->data/*initValue*/, /*allocValue*/, setPNFreeJsonPath(o,finishO(string));finishO(string)/*subSetJsonPath*/); + // cg_c bug +} internal smallJsont* setAtSmallJson(smallJsont *self, intmax_t index, baset *value) { @@ -16260,10 +15785,6 @@ internal intmax_t iterStepSmallJson(smallJsont *self) { internal baset* getSmallJson(smallJsont *self, const char *key) { - if (!key) { - return(NULL); - } - smallt *o = NULL; getJsonPath; return(toBaset(o)); @@ -16599,10 +16120,6 @@ internal smallContainert* getSmallContainerSmallJson(smallJsont *self, const cha //getNDup internal baset* getNDupSmallJson(smallJsont *self, const char *key) { - if (!key) { - return(NULL); - } - smallt *o = NULL; getNDupJsonPath; return(toBaset(sDuplicate(o))); @@ -17470,9 +16987,7 @@ internal double getNumAtSmallJson(smallJsont *self, intmax_t index) { internal smallJsont* delElemSmallJson(smallJsont *self, const char *key) { - if (self->topIsA == TOP_IS_DICT && key && self->top) { - delJsonPath; - } + delJsonPath; return(self); } @@ -19288,21 +18803,14 @@ internal bool appendTextJsonSmallJson(smallJsont *self, smallJsont *filePath) { internal const char* typeStringSmallJson(smallJsont *self, const char *key) { - if (self->topIsA == TOP_IS_DICT) { - if (!self->top) { - return(NULL); - } - - smallt *o = NULL; - typeStringJsonPath; - - if (!o) { - return(NULL); - } + smallt *o = NULL; + typeStringJsonPath; - return(SMALL_TYPE_NAMES[(size_t)o->type]); + if (!o) { + return(NULL); } - return(NULL); + + return(SMALL_TYPE_NAMES[(size_t)o->type]); } internal smallStringt* typeSmallStringSmallJson(smallJsont *self, const char *key) { @@ -19334,21 +18842,14 @@ internal smallStringt* typeSmallStringKCharSmallJson(smallJsont *self, char key) internal char typeSmallJson(smallJsont *self, const char *key) { - if (self->topIsA == TOP_IS_DICT) { - if (!self->top) { - return(0); - } - - smallt *o = NULL; - typeJsonPath; - - if (!o) { - return(0); - } + smallt *o = NULL; + typeJsonPath; - return(o->type); + if (!o) { + return(0); } - return(0); + + return(o->type); } internal char typeKCharSmallJson(smallJsont *self, char key) { @@ -19541,11 +19042,7 @@ internal bool isEBytesAtSmallJson(smallJsont *self, intmax_t index) { internal bool isETypeSmallJson(smallJsont *self, const char *key, const char *type) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top or !type) { + if (!type) { return(false); } @@ -19561,14 +19058,6 @@ internal bool isETypeSmallJson(smallJsont *self, const char *key, const char *ty internal bool isEUndefinedSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "undefined")); @@ -19581,14 +19070,6 @@ internal bool isEUndefinedSmallJson(smallJsont *self, const char *key) { internal bool isEBoolSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "bool")); @@ -19601,14 +19082,6 @@ internal bool isEBoolSmallJson(smallJsont *self, const char *key) { internal bool isEContainerSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "container")); @@ -19621,14 +19094,6 @@ internal bool isEContainerSmallJson(smallJsont *self, const char *key) { internal bool isEDictSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "dict")); @@ -19641,14 +19106,6 @@ internal bool isEDictSmallJson(smallJsont *self, const char *key) { internal bool isEDoubleSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "double")); @@ -19661,14 +19118,6 @@ internal bool isEDoubleSmallJson(smallJsont *self, const char *key) { internal bool isEIntSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "int")); @@ -19681,14 +19130,6 @@ internal bool isEIntSmallJson(smallJsont *self, const char *key) { internal bool isEStringSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "string")); @@ -19701,14 +19142,6 @@ internal bool isEStringSmallJson(smallJsont *self, const char *key) { internal bool isEFaststringSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "faststring")); @@ -19721,14 +19154,6 @@ internal bool isEFaststringSmallJson(smallJsont *self, const char *key) { internal bool isEArraySmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "array")); @@ -19741,14 +19166,6 @@ internal bool isEArraySmallJson(smallJsont *self, const char *key) { internal bool isEBytesSmallJson(smallJsont *self, const char *key) { - if (self->topIsA != TOP_IS_DICT) { - return(false); - } - - if (!self->top) { - return(false); - } - smallt *o = NULL; isEJsonPath(eqS(SMALL_TYPE_NAMES[(size_t)o->type], "bytes")); diff --git a/src/json/libsheepyCSmallJson.h b/src/json/libsheepyCSmallJson.h @@ -50,6 +50,15 @@ typedef struct smallJson smallJsont; // for object inheriting smallJson, cast to smallJson to be able to use this class functions and generics #define cJs(self) ( (smallJsont*) self ) +/** json Path Result + * enum type for key type + * NOT_A_PATH is a dictionary key + */ +typedef enum {KEY_IS_NULL=0, NOT_A_PATH, ARRAY_PATH, DICT_PATH} jsonPathRest; + +/** array to convert jsonPathRest to string */ +extern const char *jsonPathResS[]; + typedef void (*freeSmallJsonFt) (smallJsont *self); typedef void (*terminateSmallJsonFt) (smallJsont **self); typedef char* (*toStringSmallJsonFt) (smallJsont *self); @@ -60,7 +69,7 @@ typedef smallJsont* (*duplicateSmallJsonFt) (smallJsont *self); * self becomes empty. * * Useful when the objects are shared - */ + */ typedef void (*disposeSmallJsonFt) (smallJsont *self); /** @@ -239,6 +248,99 @@ typedef smallIntt* (*getTopSmallIntSmallJsonFt) (smallJsont *self); typedef smallStringt* (*getTopSmallStringSmallJsonFt)(smallJsont *self); /** + * keyIs + * determine json key type: dictionary key, json path starting from an array or json path starting from a dictionary + * + * use the jsonPathResS[] array to convert the result to string (or use keyIsS to get the result as string directly) + * + * \param + * key any key or path in self + * \return + * key type (enum int) + * 0 (KEY_IS_NULL in enum) when key is NULL + */ +typedef jsonPathRest (*keyIsSmallJsonFt) (smallJsont *self, const char *key); + +/** + * keyIs returning result as string + * determine json key type: dictionary key, json path starting from an array or json path starting from a dictionary + * + * \param + * key any key or path in self + * \return + * key type + * NULL when key is NULL + */ +typedef const char* (*keyIsSSmallJsonFt) (smallJsont *self, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * + * \param + * key key to transform + * \return + * new dictionary key (you must free this buffer) + * NULL when key is NULL + */ +typedef char* (*makeKeySmallJsonFt) (smallJsont *self, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * + * \param + * key pointer to key to transform (this parameter is reallocated) + * \return + * new dictionary key (you must free this buffer) + * NULL when key is NULL + */ +typedef char* (*iMakeKeySmallJsonFt) (smallJsont *self, char **key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * the result is stored dest, dest must be big enough (at least makeKeyLen+1) + * + * \param + * key key to transform + * \param + * dest result buffer + * \return + * dictionary key in dest + * NULL when key is NULL + */ +typedef char* (*bMakeKeySmallJsonFt) (smallJsont *self, char *dest, const char *key); + +/** + * make json key + * escape " and \ characters and add quotes to prevent misinterpreting the key as a json path + * the result is stored dest, dest size must be big enough (at least makeKeyLen+1) + * + * \param + * key key to transform + * \param + * dest result buffer + * \param + * size dest buffer size + * \return + * dictionary key in dest + * NULL when key is NULL + */ +typedef char* (*bLMakeKeySmallJsonFt) (smallJsont *self, char *dest, size_t size, const char *key); + +/** + * return key length after running makeKey + * + * \param + * key key to transform + * \return + * dictionary key length + * 0 when key is NULL + */ +typedef size_t (*makeKeyLenSmallJsonFt)(smallJsont *self, const char *key); + +/** * set element * * When the sObject pointer is updated by realloc, the sObject @@ -2402,6 +2504,13 @@ typedef bool (*areAllEBytesSmallJsonFt) (smallJsont *self); getTopSmallDoubleSmallJsonFt getTopSmallDouble;\ getTopSmallIntSmallJsonFt getTopSmallInt;\ getTopSmallStringSmallJsonFt getTopSmallString;\ + keyIsSmallJsonFt keyIs;\ + keyIsSSmallJsonFt keyIsS;\ + makeKeySmallJsonFt makeKey;\ + iMakeKeySmallJsonFt iMakeKey;\ + bMakeKeySmallJsonFt bMakeKey;\ + bLMakeKeySmallJsonFt bLMakeKey;\ + makeKeyLenSmallJsonFt makeKeyLen;\ setSmallJsonFt set;\ setUndefinedSmallJsonFt setUndefined;\ setBoolSmallJsonFt setBool;\ diff --git a/src/json/libsheepyCSmallJsonInternal.h b/src/json/libsheepyCSmallJsonInternal.h @@ -33,31 +33,47 @@ declareRecycle(smallJsont); #endif // recycleContainers #define walkJsonPath(getSmallObj, arrayCode, dictCode, returnFail, directHit, keyErrorReturn)\ - if (!findS(key, "\"") && !findS(key, "[")) {\ + ;/*avoid error: a label can only be part of a statement and a declaration is not a statement */\ + if (!key) return keyErrorReturn;\ + /* check key type */\ + jsonPathRest keyType = keyIsSmallJson(self, key);\ + if (keyType == NOT_A_PATH) {\ returnFail;\ directHit;\ }\ \ - sDictt **d = &(self->top);\ - sArrayt **a = &(self->topA);\ - smallt **oo = NULL;\ - int status = 0;\ + sDictt **d = &(self->top);\ + sArrayt **a = &(self->topA);\ + smallt **oo = NULL;\ + int status = 0;\ + bool escape = false;\ + size_t keyIdx = 0;\ \ for(size_t i = 0 ; key[i] ; i++) {\ + if (escape) {\ + escape = false;\ + continue;\ + }\ if (key[i] == '[') {\ /* array index */\ - char *next = findS((key+i+1), "]");\ + const char *next = findS((key+i+1), "]");\ if (next) {\ size_t keyLen = next - (key+i+1);\ char *keyInPath = sliceS((key+i+1), 0, keyLen);\ \ - if (oo)\ + if (oo) {\ /* oo is from the smallJson and is an array */\ a = (sArrayt **) oo;\ /* verify that d is an sArray */\ if ((*a)->type != ARRAY) {free(keyInPath);return keyErrorReturn;}\ + }\ \ - uint32_t idx = parseInt(keyInPath);\ + int64_t idx = parseInt(keyInPath);\ + /* convert python index (negative index) */\ + int64_t len = (*a)->count;\ + if (idx >= len) {free(keyInPath);return keyErrorReturn;}\ + if (idx < -len) {free(keyInPath);return keyErrorReturn;}\ + if (idx < 0) {idx = len + idx;}\ if (!*(next+1)) {\ arrayCode;\ free(keyInPath);\ @@ -75,21 +91,18 @@ declareRecycle(smallJsont); if (status == 1) {\ /* found closing quote */\ status = 0;\ - continue;\ - }\ - /* dict key */\ - status = 1;\ - char *next = findS((key+i+1), "\"");\ - if (next) {\ - size_t keyLen = next - (key+i+1);\ - char *keyInPath = sliceS((key+i+1), 0, keyLen);\ + const char *next = key+i;\ + size_t keyLen = i - keyIdx;\ + char *keyInPath = sliceS((key+keyIdx), 0, keyLen);\ \ - if (oo)\ + if (oo) {\ /* oo is from the smallJson and is a dict */\ d = (sDictt **) oo;\ /* verify that d is an sDict */\ if ((*d)->type != DICT) {free(keyInPath);return keyErrorReturn;}\ + }\ \ + unescapeKey(keyInPath, keyInPath, keyLen);\ if (!*(next+1)) {\ dictCode;\ free(keyInPath);\ @@ -100,33 +113,61 @@ declareRecycle(smallJsont); getSmallObj;\ }\ free(keyInPath);\ + continue;\ }\ + /* dict key */\ + status = 1;\ + keyIdx = i+1;\ }\ + if (key[i] == '\\' && status == 1) escape = true;\ } #define setJsonPath\ - walkJsonPath(, sArraySetTiny(*a, idx, o), sDictSetTiny(d, keyInPath, o), , sDictSetTiny(&(self->top), key, o); return self, NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, sArraySetTiny(*a, idx, o)/*arrayCode*/, sDictSetTiny(d, keyInPath, o)/*dictCode*/, /*returnFail*/, sDictSetTiny(&(self->top), key, o); return self/*directHit*/, NULL/*keyErrorReturn*/) #define setPJsonPath(objP)\ - walkJsonPath(, sArraySetP(*a, idx, objP), sDictSetP(d, keyInPath, objP), , sDictSetP(&(self->top), key, objP); return self, NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, sArraySetP(*a, idx, objP)/*arrayCode*/, sDictSetP(d, keyInPath, objP)/*dictCode*/, /*returnFail*/, sDictSetP(&(self->top), key, objP); return self/*directHit*/, NULL/*keyErrorReturn*/) #define setPNFreeJsonPath(objP, finishArg)\ - walkJsonPath(, sArraySetP(*a, idx, objP), sDictSetP(d, keyInPath, objP), , sDictSetP(&(self->top), key, objP); finishArg ; return self, NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, sArraySetP(*a, idx, objP)/*arrayCode*/, sDictSetP(d, keyInPath, objP)/*dictCode*/, /*returnFail*/, sDictSetP(&(self->top), key, objP); finishArg ; return self/*directHit*/, NULL/*keyErrorReturn*/) #define getJsonPath\ - walkJsonPath(if (!oo) {free(keyInPath);return NULL;} o = *oo, o = sArrayGetTiny(*a, idx), o = sDictGetTiny(*d, keyInPath), if (!self->top) return NULL, return toBaset(sDictGetTiny(self->top, key)), NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;} o = *oo/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} o = sArrayGetTiny(*a, idx)/*arrayCode*/, if (!*d) {free(keyInPath);return NULL;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return NULL/*returnFail*/, return toBaset(sDictGetTiny(self->top, key))/*directHit*/, NULL/*keyErrorReturn*/) #define getNDupJsonPath\ - walkJsonPath(if (!oo) {free(keyInPath);return NULL;} o = *oo, o = sArrayGetTiny(*a, idx), o = sDictGetTiny(*d, keyInPath), if (!self->top) return NULL, return toBaset(sDuplicate(sDictGetTiny(self->top, key))), NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;} o = *oo/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} o = sArrayGetTiny(*a, idx)/*arrayCode*/, if (!*d) {free(keyInPath);return NULL;} o = sDictGetTiny(*d, keyInPath)/*dictCode*/, if (!self->top) return NULL/*returnFail*/, return toBaset(sDuplicate(sDictGetTiny(self->top, key)))/*directHit*/, NULL/*keyErrorReturn*/) #define delJsonPath\ - walkJsonPath(, sArrayDelTiny(*a, idx), sDictDelTiny(*d, keyInPath), if (!self->top) return NULL, sDictDelTiny(self->top, key) ; return self, NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} sArrayDelTiny(*a, 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*/, NULL/*keyErrorReturn*/) #define typeStringJsonPath\ - walkJsonPath(, o = sArrayGetTiny(*a, idx), o = sDictGetTiny(*d, keyInPath), if (!self->top) return NULL, o = sDictGet(self->top, key) ; if (!o) return NULL; return SMALL_TYPE_NAMES[(size_t)o->type], NULL) + walkJsonPath(if (!oo) {free(keyInPath);return NULL;}/*getSmallObj*/, if (!*a) {free(keyInPath);return NULL;} o = sArrayGetTiny(*a, 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*/, NULL/*keyErrorReturn*/) #define typeJsonPath\ - walkJsonPath(, o = sArrayGetTiny(*a, idx), o = sDictGetTiny(*d, keyInPath), if (!self->top) return 0, o = sDictGet(self->top, key) ; if (!o) return 0; return o->type, 0) + walkJsonPath(if (!oo) {free(keyInPath);return 0;}/*getSmallObj*/, if (!*a) {free(keyInPath);return 0;} o = sArrayGetTiny(*a, 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*/, 0/*keyErrorReturn*/) #define isEJsonPath(test)\ - walkJsonPath(, o = sArrayGetTiny(*a, idx), o = sDictGetTiny(*d, keyInPath), if (!self->top) return 0, o = sDictGet(self->top, key) ; if (!o) return false; return test, 0) + walkJsonPath(if (!oo) {free(keyInPath);return 0;}/*getSmallObj*/, if (!*a) {free(keyInPath);return 0;} o = sArrayGetTiny(*a, 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*/, 0/*keyErrorReturn*/) + +#define mainSetJsonPath(initValue, allocValue, subSetJsonPath) \ + smallt *o = NULL;\ + if (!key)\ + return NULL;\ + jsonPathRest keyType = keyIsSmallJson(self, key);\ + if (self->topIsA != SMALLJSON_IS_EMPTY && ((keyType == ARRAY_PATH && (self->topIsA != TOP_IS_ARRAY && self->topIsA != SMALLJSON_IS_EMPTY)) || ((keyType == NOT_A_PATH || keyType == DICT_PATH) && (self->topIsA != TOP_IS_DICT && self->topIsA != SMALLJSON_IS_EMPTY))))\ + return NULL;\ + initValue;\ + switch(self->topIsA) {\ + case SMALLJSON_IS_EMPTY:\ + if (keyType == NOT_A_PATH || keyType == DICT_PATH)\ + self->topIsA = TOP_IS_DICT;\ + else if (keyType == ARRAY_PATH)\ + self->topIsA = TOP_IS_ARRAY;\ + case TOP_IS_ARRAY:\ + case TOP_IS_DICT:;\ + allocValue;\ + subSetJsonPath;\ + break;\ + }\ + return self + diff --git a/src/json/libsheepyObjectTest.c b/src/json/libsheepyObjectTest.c @@ -667,16 +667,14 @@ START_TEST(cSmallJsonT) ck_assert_ptr_eq(in, NULL); // missing " at the end in = (smallIntt *) obj2->f->get(obj2, "\"dict\".\"int2"); - ck_assert(isOType(in, "smallDict")); - finishO(in); + ck_assert_ptr_eq(in, NULL); // get array element in = (smallIntt *) obj2->f->get(obj2, "\"array\"[0]"); ck_assert(in->value->value == 123); smashO(in); // missing ] at the end in = (smallIntt *) obj2->f->get(obj2, "\"array\"[0"); - ck_assert(isOType(in, "smallArray")); - finishO(in); + ck_assert_ptr_eq(in, NULL); // json array createAllocateSmallJson(json); createAllocateSmallInt(oInt4); @@ -686,6 +684,92 @@ START_TEST(cSmallJsonT) in = (smallIntt *) json->f->get(json, "[0]"); ck_assert(in->value->value == 345); smashO(in); + // set get json path + createSmallJson(jpath); + // dict is top + jpath.f->parse(&jpath, "{ \"a\": {\"a\": true}, \"b\": 234, \"c\": [\"qwe\",32]}"); + // get non existing element in 'c' array + b = jpath.f->get(&jpath,"\"c\"[3]"); + ck_assert_ptr_eq(b, NULL); + finishO(b); + // dictionary keys should not be unescaped + createSmallBool(ba); + jpath.f->set(&jpath, "b\\\\", cBa(&ba)); + jBool = (smallBoolt*)jpath.f->get(&jpath,"b\\\\"); + ck_assert(jBool->value->value == false); + finishO(jBool); + // keys in json paths should be unescaped + createSmallBool(bb); + bb.f->set(&bb, true); + jpath.f->set(&jpath, "\"b\\\\\"", (baset*)&bb); + jBool = (smallBoolt*)jpath.f->get(&jpath,"\"b\\\\\""); + ck_assert(jBool->value->value == true); + finishO(jBool); + freeO(&jpath); + // array is top + // get dict in dict + jpath.f->parse(&jpath, "[1,{\"a\": {\"a\": true}, \"b\": 234, \"c\": [\"qwe\",32]}, [[11],22,33]]"); + b = jpath.f->get(&jpath,"[1].\"a\""); + ck_assert_str_eq(b->type, "smallDict"); + finishO(b); + // get bool in dict + jBool = (smallBoolt*)jpath.f->get(&jpath,"[1]\"a\"\"a\""); + ck_assert(jBool->value->value == true); + finishO(jBool); + // get array in array + jArray = (smallArrayt*)jpath.f->get(&jpath,"[2][0]"); + ck_assert_str_eq(jArray->type, "smallArray"); + ck_assert_uint_eq(lenO(jArray), 1); + finishG(jArray); + // get element in array + in = (smallIntt*)(jpath.f->get(&jpath,"[2][0][0]")); + ck_assert_uint_eq(in->value->value, 11); + finishG(in); + // set element in array with negative index + createSmallBool(be); + jpath.f->set(&jpath, "[-1][0][0]", (baset*)&be); + // get element in array with negative index + jBool = (smallBoolt*)jpath.f->get(&jpath,"[-1][0][0]"); + ck_assert(jBool->value->value == false); + finishG(jBool); + // set new element in dict + createSmallBool(b2); + o2 = jpath.f->set(&jpath, "[1]\"a\"\"b\\\"\"", (baset*)&b2); + ck_assert_ptr_ne(o2, NULL); + jBool = (smallBoolt*)jpath.f->get(&jpath,"[1]\"a\"\"b\\\"\""); + ck_assert(jBool->value->value == false); + finishG(jBool); + createSmallBool(b3); + o2 = jpath.f->set(&jpath, "[1]\"a\"\"b\\\\\"", (baset*)&b3); + ck_assert_ptr_ne(o2, NULL); + jBool = (smallBoolt*)jpath.f->get(&jpath,"[1]\"a\"\"b\\\\\""); + ck_assert(jBool->value->value == false); + finishG(jBool); + // escape key in json path + // \\\"" + char *ks = jpath.f->makeKey(&jpath, "\\\\\\\"\""); + ck_assert_str_eq(ks, "\"\\\\\\\\\\\\\\\"\\\"\""); + createSmallBool(b4); + iPrependS(&ks, "[1]"); + o2 = jpath.f->set(&jpath, ks, (baset*)&b4); + ck_assert_ptr_ne(o2, NULL); + jBool = (smallBoolt*)jpath.f->get(&jpath,ks); + ck_assert(jBool->value->value == false); + finishG(jBool); + free(ks); + // wrong path + b = jpath.f->get(&jpath,"[3][0][0]"); + ck_assert_ptr_eq(b, NULL); + finishG(b); + // missing index + b = jpath.f->get(&jpath,"[][0][0]"); + ck_assert_ptr_eq(b, NULL); + finishG(b); + // try to assign dictionary key to array, wrong + createSmallBool(b0); + o2 = jpath.f->set(&jpath, "[2][0]\"sdf\\\"", (baset*)&b0); + ck_assert_ptr_eq(o2, NULL); + freeO(&jpath); // len initiateAllocateSmallJson(&o); ck_assert_uint_eq(o->f->len(o), 0); diff --git a/src/libsheepy.c b/src/libsheepy.c @@ -54071,10 +54071,10 @@ void scheduler(void) { +#if ((__GNUC__ > 4)) /** * return monotonic time in nanoseconds */ -#if ((__GNUC__ > 4)) uint64_t getMonotonicTime(void) { struct timespec ts; diff --git a/src/libsheepy.h b/src/libsheepy.h @@ -96,7 +96,7 @@ // version accoring to the version package: Release.Major.minor.patch // https://noulin.net/version/file/README.md.html -#define LIBSHEEPY_VERSION "1.0.5.1" +#define LIBSHEEPY_VERSION "1.0.6" #ifndef SH_PREFIX #define SH_PREFIX(NAME) NAME @@ -301,6 +301,20 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; #define f32 float #define f64 double +/** + * type cast + */ +#define I8(value) (i8)(value) +#define I16(value) (i16)(value) +#define I32(value) (i32)(value) +#define I64(value) (i64)(value) +#define U8(value) (u8)(value) +#define U16(value) (u16)(value) +#define U32(value) (u32)(value) +#define U64(value) (u64)(value) +#define F32(value) (f32)(value) +#define F64(value) (f64)(value) + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN3(a, b, c) MIN((typeof(a))MIN(a, b), c) @@ -401,6 +415,12 @@ extern jmp_buf tryJumpBuffers[maxTryThrowCount]; */ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +/** true when value is odd integer */ +#define isIntOdd(value) (value&1) + +/** true when value is even integer */ +#define isIntEven(value) (!(value&1)) + /** * typ definition as alternative to typedef */ diff --git a/src/libsheepyObject.h b/src/libsheepyObject.h @@ -8349,6 +8349,9 @@ void finishManyOF(void *paramType, ...); */ typedef struct base baset; +// for object inheriting baset, cast to baset to be able to use this class functions and generics +#define cBa(self) ( (baset*) self ) + // Functions /** @@ -8551,6 +8554,9 @@ extern smallContainert* rtSmallContainert; */ #define _ "\"" +/** Back Slash string to escape back slash, use in for example json path with get, set... */ +#define BSLH "\\" + /** * get a pointer to the string in the smallString object *