From b3804dcf50e71e01d1d4fc9d6689cdf44f949844 Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Sat, 10 Nov 2018 23:37:33 +0500 Subject: [PATCH] Implement custom pool API Now it's poosible to use any custom pool allocation, i.e preallocated pools or dymamic allocation on fly. --- example-03.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 8 +++- tiny-json.c | 33 +++++++++----- tiny-json.h | 20 +++++++++ 4 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 example-03.c diff --git a/example-03.c b/example-03.c new file mode 100644 index 0000000..d9a37b6 --- /dev/null +++ b/example-03.c @@ -0,0 +1,121 @@ + +/* + + + + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2016-2018 Rafa Garcia . + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +/* + * In this example the JSON library is used to analyze an object that some + * properties are expected. + */ + +#include +#include +#include +#include "tiny-json.h" + +typedef struct jsonStaticPool_s { + json_t mem[32]; + unsigned int nextFree; + jsonPool_t pool; +} jsonStaticPool_t; + +static json_t* poolInit( jsonPool_t* pool ) { + jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool); + spool->nextFree = 1; + return &spool->mem[0]; +} + +static json_t* poolNew( jsonPool_t* pool ) { + jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool); + if ( spool->nextFree >= sizeof spool->mem / sizeof spool->mem[0] ) return 0; + return &spool->mem[spool->nextFree++]; +} + +/* Parser a json string. */ +int main( void ) { + char str[] = "{\n" + "\t\"firstName\": \"Bidhan\",\n" + "\t\"lastName\": \"Chatterjee\",\n" + "\t\"age\": 40,\n" + "\t\"address\": {\n" + "\t\t\"streetAddress\": \"144 J B Hazra Road\",\n" + "\t\t\"city\": \"Burdwan\",\n" + "\t\t\"state\": \"Paschimbanga\",\n" + "\t\t\"postalCode\": \"713102\"\n" + "\t},\n" + "\t\"phoneList\": [\n" + "\t\t{ \"type\": \"personal\", \"number\": \"09832209761\" },\n" + "\t\t{ \"type\": \"fax\", \"number\": \"91-342-2567692\" }\n" + "\t]\n" + "}\n"; + puts( str ); + jsonStaticPool_t spool = { .pool = { .init = poolInit, .new = poolNew } }; + json_t const* json = json_create_pool( str, &spool.pool ); + if ( !json ) { + puts("Error json create."); + return EXIT_FAILURE; + } + + json_t const* firstName = json_getProperty( json, "firstName" ); + if ( !firstName || JSON_TEXT != json_getType( firstName ) ) { + puts("Error, the first name property is not found."); + return EXIT_FAILURE; + } + char const* firstNameVal = json_getValue( firstName ); + printf( "Fist Name: %s.\n", firstNameVal ); + + char const* lastName = json_getPropertyValue( json, "lastName" ); + if ( !lastName ) { + puts("Error, the last name property is not found."); + return EXIT_FAILURE; + } + printf( "Last Name: %s.\n", lastName ); + + json_t const* age = json_getProperty( json, "age" ); + if ( !age || JSON_INTEGER != json_getType( age ) ) { + puts("Error, the age property is not found."); + return EXIT_FAILURE; + } + int const ageVal = (int)json_getInteger( age ); + printf( "Age: %d.\n", ageVal ); + + json_t const* phoneList = json_getProperty( json, "phoneList" ); + if ( !phoneList || JSON_ARRAY != json_getType( phoneList ) ) { + puts("Error, the phone list property is not found."); + return EXIT_FAILURE; + } + + json_t const* phone; + for( phone = json_getChild( phoneList ); phone != 0; phone = json_getSibling( phone ) ) { + if ( JSON_OBJ == json_getType( phone ) ) { + char const* phoneNumber = json_getPropertyValue( phone, "number" ); + if ( phoneNumber ) printf( "Number: %s.\n", phoneNumber ); + } + } + + return EXIT_SUCCESS; +} diff --git a/makefile b/makefile index d184b74..1549fff 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ -build: example-01.exe example-02.exe +build: example-01.exe example-02.exe example-03.exe clean: rm -rf *.o @@ -17,6 +17,9 @@ example-01.exe: example-01.o tiny-json.o example-02.exe: example-02.o tiny-json.o gcc -std=c99 -Wall -o example-02.exe example-02.o tiny-json.o +example-03.exe: example-03.o tiny-json.o + gcc -std=c99 -Wall -o example-03.exe example-03.o tiny-json.o + test.exe: tests.o tiny-json.o gcc -std=c99 -Wall -o test.exe tests.o tiny-json.o @@ -29,5 +32,8 @@ example-01.o: example-01.c tiny-json.h example-02.o: example-02.c tiny-json.h gcc -std=c99 -Wall -c example-02.c +example-03.o: example-03.c tiny-json.h + gcc -std=c99 -Wall -c example-03.c + tests.o: tests.c tiny-json.h gcc -std=c99 -Wall -c tests.c diff --git a/tiny-json.c b/tiny-json.c index f1d6d20..ecc2aca 100644 --- a/tiny-json.c +++ b/tiny-json.c @@ -32,11 +32,12 @@ #include "tiny-json.h" /** Structure to handle a heap of JSON properties. */ -typedef struct jsonPool_s { +typedef struct jsonStaticPool_s { json_t* const mem; /**< Pointer to array of json properties. */ unsigned int const qty; /**< Length of the array of json properties. */ unsigned int nextFree; /**< The index of the next free json property. */ -} jsonPool_t; + jsonPool_t pool; +} jsonStaticPool_t; /* Search a property by its name in a JSON object. */ json_t const* json_getProperty( json_t const* obj, char const* property ) { @@ -66,19 +67,27 @@ static char* setToNull( char* ch ); static bool isEndOfPrimitive( char ch ); /* Parse a string to get a json. */ -json_t const* json_create( char* str, json_t mem[], unsigned int qty ) { +json_t const* json_create_pool( char* str, jsonPool_t* pool ) { char* ptr = goBlank( str ); if ( !ptr || *ptr != '{' ) return 0; - jsonPool_t pool = { .mem = mem, .qty = qty }; - json_t* obj = poolInit( &pool ); + json_t* obj = pool->init( pool ); obj->name = 0; obj->sibling = 0; obj->u.c.child = 0; - ptr = objValue( ptr, obj, &pool ); + ptr = objValue( ptr, obj, pool ); if ( !ptr ) return 0; return obj; } +/* Parse a string to get a json. */ +json_t const* json_create( char* str, json_t mem[], unsigned int qty ) { + jsonStaticPool_t spool = { + .mem = mem, .qty = qty, + .pool = { .init = poolInit, .new = poolNew } + }; + return json_create_pool( str, &spool.pool ); +} + /** Get a special character with its escape character. Examples: * 'b' -> '\b', 'n' -> '\n', 't' -> '\t' * @param ch The escape character. @@ -335,7 +344,7 @@ static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) { ++ptr; continue; } - json_t* property = poolNew( pool ); + json_t* property = pool->new( pool ); if ( !property ) return 0; if( obj->type != JSON_ARRAY ) { if ( *ptr != '\"' ) return 0; @@ -374,8 +383,9 @@ static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) { * @param pool The handler of the pool. * @return a instance of a json. */ static json_t* poolInit( jsonPool_t* pool ) { - pool->nextFree = 1; - return &pool->mem[0]; + jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool); + spool->nextFree = 1; + return &spool->mem[0]; } /** Create an instance of a json from a pool. @@ -383,8 +393,9 @@ static json_t* poolInit( jsonPool_t* pool ) { * @retval The handler of the new instance if success. * @retval Null pointer if the pool was empty. */ static json_t* poolNew( jsonPool_t* pool ) { - if ( pool->nextFree >= pool->qty ) return 0; - return &pool->mem[pool->nextFree++]; + jsonStaticPool_t* spool = json_container_of(pool, jsonStaticPool_t, pool); + if ( spool->nextFree >= spool->qty ) return 0; + return &spool->mem[spool->nextFree++]; } /** Checks whether an character belongs to set. diff --git a/tiny-json.h b/tiny-json.h index fd8b238..d5e5d28 100644 --- a/tiny-json.h +++ b/tiny-json.h @@ -34,10 +34,15 @@ extern "C" { #endif +#include #include #include #include +#define json_container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) + /** @defgroup tinyJson Tiny JSON parser. * @{ */ @@ -61,6 +66,13 @@ typedef struct json_s { jsonType_t type; } json_t; +/** Structure to handle a heap of JSON properties. */ +typedef struct jsonPool_s jsonPool_t; +typedef struct jsonPool_s { + json_t* (*init) ( jsonPool_t* pool ); + json_t* (*new) ( jsonPool_t* pool ); +} jsonPool_t; + /** Parse a string to get a json. * @param str String pointer with a JSON object. It will be modified. * @param mem Array of json properties to allocate. @@ -70,6 +82,14 @@ typedef struct json_s { * This property is always unnamed and its type is JSON_OBJ. */ json_t const* json_create( char* str, json_t mem[], unsigned int qty ); +/** Parse a string to get a json. + * @param str String pointer with a JSON object. It will be modified. + * @param pool Custom json pool pointer. + * @retval Null pointer if any was wrong in the parse process. + * @retval If the parser process was successfully a valid handler of a json. + * This property is always unnamed and its type is JSON_OBJ. */ +json_t const* json_create_pool( char* str, jsonPool_t *pool ); + /** Get the name of a json property. * @param json A valid handler of a json property. * @retval Pointer to null-terminated if property has name.