#include #include #include #include #include "common.h" #include "json.h" /** * TODO: 1. Redo the json_obj structure to be able to hold several. * Now only hols several members and pairs. Can hold several. * 2. Save to file * 3. Encoding of values; e.g unicode values and special chars. * 4. json_from_file; parser? **/ /** * Structure: json_type * Typedef: json_type_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Type of an JSON-entry. * * Description: * Holds the type of an JSON-entry. **/ struct json_type { json_types_t type; }; /** * JSON-entry types **/ /** * Structure: * Typedef: * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST) * json_mem_t *members: JSON-meners entries. * print_type_t ptype: Print type, eg Pretty print. * int code: Status code. * * Description: * Defines an JSON-object. **/ struct json_obj { json_types_t type; json_mem_t *members; print_type_t ptype; json_printf_t *pfunc; FILE *jfile; int code; }; /** * Structure: json_mem * Typedef: json_mem_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST) * void *entry: Containing entry. Either pair or new member * void *next: Simblings; other members or pairs in parent. * * Description: * Defines an JSON-member entry **/ struct json_mem { json_types_t type; void *entry; void *next; }; /** * Structure: json_elem * Typedef: json_elem_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST). * void *entry: Containing entry. Either value or new element. * void *next: Simblings; other elements in parent. * * Description: * Defines an JSON-element entry. **/ struct json_elem { json_types_t type; void *entry; void *next; }; /** * Structure: json_pair * Typedef: json_pair_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST). * char *str: String specifier. * json_val_t *value; Containing entry, only value. * void *next: Simblings; other members or pairs in parent. * * Description: * **/ struct json_pair { json_types_t type; char *str; json_val_t *value; void *next; }; /** * Structure: json_arr * Typedef: json_arr_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST). * void *entry: Containing entry, only elements. * * Description: * Defines a JSON-array entry. **/ struct json_arr { json_types_t type; json_elem_t *entry; }; /** * Structure: json_val * Typedef: json_val_t * Author: Joachim M. Giæver * * Sections: * json_types_t type: Entry type (MUST BE FIRST). * json_types_t sub_type: Type of the sub entry, eg JSON_INT, _CHAR etc * void *value: The actual entry * * Description: * **/ struct json_val { json_types_t type; json_types_t sub_type; void *value; }; /** * Function: json_ptype * Author: Joachim M. Giæver * * Parameters: * - print_type_t ptype: Print type * * Description: * Validates and sets the print type, e.g * Pretty Print, Print etc. (File save not implemented) * * Returns: int, the print type value **/ static int json_ptype( print_type_t ptype ); /** * Function: json_set_code * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object to set status for * - int code: The status code to set * * Description: * Sets the status code of the last event * of types related to the JSON-object. * * Returns: int, the newly set code **/ static int json_set_code( json_obj_t *jobj, int code ); /** * Function: json_get_type * Author: Joachim M. Giæver * * Parameters: * - void *entry: The JSON-entry to read type of * * Description: * Returns the type of the JSON-entry. * * Returns: json_types_t, the type **/ static json_types_t json_get_type( void *entry ); /** * Function: json_is_type * Author: Joachim M. Giæver * * Parameters: * - void *entry: The JSON-entry to check * - json_types_t: The JSON-type compare against * * Description: * Checks the equality of the type of the entry * agains the given type. * * Returns: int, 1 on success, 0 on failure **/ static int json_is_type( void *entry, json_types_t jtype ); /** * Function: json_uninit_obj * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: The JSON-object (parent of obj) * - void *obj: Any kind of object within parent * * Description: * Checks if the JSON-object is uninitialized. Checks * both the root (jobj) and sub obj. * * Returns: int, 1 on failure, 0 on success **/ static int json_uninit_obj( json_obj_t *jobj, void *obj ); /** * Function: json_val_vtype * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: Parent JSON-object * - json_types_t *vtype: The value type * * Description: * Checks if the given type is valid as a value, for * the value entry. * * Returns: int, 1 on success, 0 on failure **/ static int json_val_vtype( json_obj_t *jobj, json_types_t vtype ); /** * Function: json_insert * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: Parent JSON-obj * - void *root: Root-entry, an JSON-entry * - void *entry: New entry, valid for root-entry * * Description: * Inserts an entry into the root, which is related * to the parent JSON-obj. Insertion method and possibilities * depends on the root-entry. * * Returns: void *, address to newly inserte entry **/ static void *json_insert( json_obj_t *jobj, void *root, void *entry ); /** Recursice functions to print the tree **/ static void _json_out( json_obj_t *jobj, int height ); static void _print_( json_obj_t *jobj, ... ); static void _print_mem( json_obj_t *jobj, json_mem_t *jmem, int height ); static void _print_pair( json_obj_t *jobj, json_pair_t *jpair, int height ); static void _print_arr( json_obj_t *jobj, json_arr_t *jarr, int height ); static void _print_elem( json_obj_t *jobj, json_elem_t *jelem, int height ); static void _print_value( json_obj_t *jobj, json_val_t *jval, int height ); static char *_print_set_newline( json_obj_t *jobj ); static void _print_tabs_release( char *tabs ); static char *_print_tabs( json_obj_t *jobj, int height ); /** Silence in comments is like nothing was here */ /** * Function: json_create * Author: Joachim M. Giæver * * Parameters: * - char *fname: The filename; on saving and possible parsing - in the future. * - print_type_t ptype: Store/print type * * Description: * Creates the main root of the JSON-structure. * * Returns: json_obj_t *, the mother root **/ json_obj_t *json_create( char *fname, print_type_t ptype ) { json_obj_t *jobj = ( json_obj_t *) malloc( sizeof( json_obj_t ) ); if ( jobj == NULL ) errandend( "Could not allocate memory for JSON object" ); jobj->type = JSON_OBJ; jobj->members = NULL; jobj->ptype = json_ptype( ptype ); if ( (jobj->ptype & JSON_SAVE_FILE) == JSON_SAVE_FILE ) { jobj->jfile = fopen( fname, "w+" ); if ( jobj->jfile == NULL ) { printf("%s\n", fname ); errandend( "Could not open file for reading/writing." ); } jobj->pfunc = (json_printf_t *)fprintf; } else { jobj->jfile = NULL; jobj->pfunc = (json_printf_t *)printf; } json_set_code( jobj, jobj->ptype ); return jobj; } /** * Function: json_destroy * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object to destroy * * Description: * Destroys any kind of JSON-objects * * Returns: void **/ void json_destroy( json_obj_t *jobj ) { if ( jobj == NULL ) return; if ( jobj->members != NULL ) json_destroy_mem( jobj->members ); if ( jobj->jfile != NULL ) fclose( jobj->jfile ); free( jobj ); } /** * Function: json_create_obj * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * - json_val_t *jval: JSON-value to insert to * * Description: * Creates a new JSON-object to insert into the * JSON-structure (only into JSON-value.). * * Works recursivly on children. * * Returns: json_obj_t *, JSON-object **/ json_obj_t *json_create_obj( json_obj_t *jobj, json_val_t *jval ) { json_obj_t *jcobj; if ( json_uninit_obj( jobj, jval ) ) return NULL; jcobj = json_create( "", jobj->ptype ); if ( json_insert( jobj, jval, jobj ) != NULL ) return jcobj; json_destroy( jcobj ); return NULL; } /** * Function: json_create_mem * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object to insert to * * Description: * Creates a new JSON-member and inserts it into the * JSON-object. May be any kind of JSON-object, both * root or children. * * Returns: json_mem_t *, JSON-member **/ json_mem_t *json_create_mem( json_obj_t *jobj ) { json_mem_t *jmem; if ( json_has_err( jobj ) ) return NULL; jmem = ( json_mem_t *) malloc( sizeof( json_mem_t ) ); if ( jmem == NULL ) { json_set_code( jobj, JSON_NOMEM ); return NULL; } jmem->type = JSON_MEM; jmem->entry = NULL; jmem->next = NULL; if ( json_insert( jobj, jobj, jmem ) != NULL ) return jmem; json_destroy_mem( jmem ); return NULL; } /** * Function: json_destroy_mem * Author: Joachim M. Giæver * * Parameters: * - json_mem_t *jmem: JSON-member to destroy * * Description: * Destroy a JSON-member, works recursively on both simblings * and children. * * Returns: void **/ void json_destroy_mem( json_mem_t *jmem ) { if ( jmem == NULL ) return; if ( jmem->entry != NULL ) { if ( json_is_type( jmem->entry, JSON_PAIR ) ) json_destroy_pair( jmem->entry ); else json_destroy_mem( jmem->entry ); } if ( jmem->next != NULL ) { if ( json_is_type( jmem->next, JSON_PAIR ) ) json_destroy_pair( jmem->next ); else json_destroy_mem( jmem->next ); } free( jmem ); } /** * Function: json_create_pair * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * - json_mem_t *jmem: JSON-member to insert to * * Description: * Creates a new JSON-pair and inserts it into a JSON-member. * * Returns: json_pair_t *, JSON-pair **/ json_pair_t *json_create_pair( json_obj_t *jobj, json_mem_t *jmem, char *str ) { json_pair_t *jpair; if ( json_uninit_obj( jobj, jmem ) ) return NULL; jpair = ( json_pair_t *) malloc( sizeof( json_pair_t ) ); if ( jpair == NULL ) { json_set_code( jobj, JSON_NOMEM ); return NULL; } jpair->type = JSON_PAIR; jpair->str = strdup( str ); jpair->value = NULL; jpair->next = NULL; if ( json_insert( jobj, jmem, jpair ) != NULL ) return jpair; json_destroy_pair( jpair ); return NULL; } /** * Function: json_destroy_pair * Author: Joachim M. Giæver * * Parameters: * - json_pair_t *jpair: JSON-pair to destroy * * Description: * Destroys a JSON-pair. Works recursively on both the simblings * and children. * * Returns: void **/ void json_destroy_pair( json_pair_t *jpair ) { if ( jpair == NULL ) return; if ( jpair->value != NULL ) json_destroy_value( jpair->value ); if ( jpair->next != NULL ) { if ( json_is_type( jpair->next, JSON_PAIR ) ) json_destroy_pair( jpair->next ); else json_destroy_mem( jpair->next ); } free( jpair->str ); free( jpair ); } /** * Function: json_create_arr * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * - json_val_t *jval: JSON-value to insert to * * Description: * Creates a new JSON-array and inserts it into JSON-value. * * Returns: json_arr_t *, JSON-array **/ json_arr_t *json_create_arr( json_obj_t *jobj, json_val_t *jval ) { json_arr_t *jarr; if ( json_uninit_obj( jobj, jval ) ) return NULL; jarr = ( json_arr_t *) malloc( sizeof( json_arr_t ) ); if ( jarr == NULL ) { json_set_code( jobj, JSON_NOMEM ); return NULL; } jarr->type = JSON_ARR; jarr->entry = NULL; if ( json_insert( jobj, jval, jarr ) != NULL ) return jarr; json_destroy_arr( jarr ); return NULL; } /** * Function: json_destroy_arr * Author: Joachim M. Giæver * * Parameters: * - json_arr_t *jarr: JSON-array to destroy * * Description: * Destroys a JSON-array. Works recursively on the children. * * Returns: void **/ void json_destroy_arr( json_arr_t *jarr ) { if ( jarr == NULL ) return; if ( jarr->entry != NULL ) json_destroy_elem( jarr->entry ); free( jarr ); } /** * Function: json_create_elem * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * - json_arr_t *jarr: JSON-array to insert into * * Description: * Creates a JSON-element and inserts it int an JSON-array. * * Returns: json_elem_t *, JSON-element **/ json_elem_t *json_create_elem( json_obj_t *jobj, json_arr_t *jarr ) { json_elem_t *jelem; if ( json_uninit_obj( jobj, jarr ) ) return NULL; jelem = ( json_elem_t *) malloc( sizeof( json_elem_t ) ); if ( jelem == NULL ) { json_set_code( jobj, JSON_NOMEM ); return NULL; } jelem->type = JSON_ELEM; jelem->entry = NULL; jelem->next = NULL; if ( json_insert( jobj, jarr, jelem ) != NULL ) return jelem; json_destroy_elem( jelem ); return NULL; } /** * Function: json_destroy_elem * Author: Joachim M. Giæver * * Parameters: * - json_elem_t *jelem: JSON-element to destroy * * Description: * Destroys a JSON-element. Works recursively on both simblings * and children. * * Returns: void **/ void json_destroy_elem( json_elem_t *jelem ) { if ( jelem == NULL ) return; if ( jelem->entry != NULL ) json_destroy_value( jelem->entry ); if ( jelem->next != NULL ) json_destroy_elem( jelem->next ); free( jelem ); } /** * Function: json_insert_value * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * - void *ins_obj: Object or element to insert into * - json_types_t vtype: Type of the held element in value * - void *entry: Entry to store in value * * Description: * Creates a new JSON-value and inserts it into a JSON-element or * a JSON-pair. The value must also be specified. JSON-object and * JSON-array can be insert upon creation by setting entry as NULL. * * Ex: * * // Insert this value into a JSON-pair, will contain an JSON-array * json_val_t *jvalue = json_insert_value( jobj, jpair, JSON_ARR, NULL ); * * // Create the JSON-array and insert it into the above value * json_arr_t *jarr = json_create_arr( jobj, jval ); * * Returns: json_val_t *, JSON-value **/ json_val_t *json_insert_value( json_obj_t *jobj, void *ins_obj, json_types_t vtype, void *entry ) { json_val_t *jval; if ( vtype != JSON_NULL && ( ( vtype != JSON_OBJ && vtype != JSON_ARR && json_uninit_obj( jobj, entry ) ) || json_val_vtype( jobj, vtype ) < 0 ) ) return NULL; jval = ( json_val_t *) malloc( sizeof( json_val_t ) ); if ( jval == NULL ) { json_set_code( jobj, JSON_NOMEM ); return NULL; } jval->type = JSON_VAL; jval->sub_type = vtype; if ( vtype == JSON_OBJ || vtype == JSON_ARR ) { /* By now; nothing to do */ } else { switch( vtype ) { case JSON_CHAR: jval->value = strdup( (char *)entry ); break; case JSON_INT: jval->value = (int *) malloc( sizeof( int ) ); memcpy( jval->value, ((const void *)entry), sizeof( int ) ); break; case JSON_FLOAT: jval->value = (float *) malloc( sizeof( int ) ); memcpy( jval->value, ((const void *)entry), sizeof( float ) ); break; case JSON_BOOL: jval->value = strdup( *((bool *)entry) == true ? "true" : "false" ); break; case JSON_NULL: jval->value = strdup( entry == NULL ? "null" : "" ); break; default: json_set_code( jobj, JSON_INVALID_VAL_TYPE ); break; } json_set_code( jobj, JSON_INS_VAL_VAL ); } if ( json_insert( jobj, ins_obj, jval ) != NULL ) return jval; json_destroy_value( jval ); return NULL; } /** * Function: json_destroy_value * Author: Joachim M. Giæver * * Parameters: * - json_val_t *jval: JSON-value to destroy * * Description: * Destroys a JSON-value. Works recursively on children. * * Returns: void **/ void json_destroy_value( json_val_t *jval ) { if ( jval == NULL ) return; switch( jval->sub_type ) { case JSON_OBJ: json_destroy( jval->value );; break; case JSON_ARR: json_destroy_arr( jval->value ); break; case JSON_CHAR: case JSON_INT: case JSON_FLOAT: case JSON_BOOL: case JSON_NULL: free( jval->value ); break; default: break; } free( jval ); } /** * Function: json_has_err * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * * Description: * Returns whether or not there was an error present on last event. * * Returns: int 0 on non errors 1 on errors **/ int json_has_err( json_obj_t *jobj ) { if ( jobj == NULL ) return JSON_UNINITALIZED_OJB; return ( jobj->code >= 0 ? 0 : 1 ); } /** * Function: json_last_err * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * * Description: * Returns the last error code present. * * Returns: int, >= 0 on non errors <= 0 on errors **/ int json_last_err( json_obj_t *jobj ) { if ( jobj == NULL ) return JSON_UNINITALIZED_OJB; return jobj->code; } /** * Function: json_last_errmsg * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * * Description: * Returns the error message related to the error code * stored in the JSON-object (remember to check for errors; json_has_err). * * Returns: char *, error message **/ const char *json_last_errmsg( json_obj_t *jobj ) { char *errmsg; int errcode = json_last_err( jobj ); switch( errcode ) { case JSON_NO_REPORT: errmsg = "Not an error"; break; case JSON_UNKNOWN_PTYPE: errmsg = "Unknown print type"; break; case JSON_UNINITALIZED_OJB: errmsg = "Un-initialized JSON object"; break; case JSON_NOMEM: errmsg = "Out of memory"; break; case JSON_INVALID_VAL_TYPE: errmsg = "Invalid type to insert within value object"; break; case JSON_INVALID_ROOT_ENT: case JSON_INVALID_OBJ_ENT: case JSON_INVALID_MEM_ENT: case JSON_INVALID_PAIR_ENT: case JSON_INVALID_ELE_MENT: case JSON_INVALID_VAL_ENT: case JSON_INVALID_ELEM_ENT: case JSON_INVALID_ARR_ENT: errmsg = "Invalid object to insert within parent object"; break; case JSON_MIXED_VAL_AND_TYPE: errmsg = "Mixed value and type."; break; default: errmsg = "Error code unknown or not implemented"; break; } return (const char *)errmsg; } /** * Function: json_out * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object which is the main-root * * Description: * Recursively prints the JSON-object. * * Returns: void **/ void json_out( json_obj_t *jobj ) { int height = 1; _print_( jobj, "[%s", _print_set_newline(jobj) ); _json_out( jobj, height ); _print_( jobj, "]%s", _print_set_newline(jobj) ); } /** * Function: json_ptype * Author: Joachim M. Giæver * * Parameters: * - print_type_t ptype: Print type * * Description: * Validates and sets the print type, e.g * Pretty Print, Print etc. (File save not implemented) * * Returns: int, the print type value **/ static int json_ptype( print_type_t ptype ) { return ( ptype > JSON_SAVE_FILE - 1 && ptype < JSON_TYPE ? ptype : JSON_UNKNOWN_PTYPE ); } /** * Function: json_set_code * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: JSON-object to set status for * - int code: The status code to set * * Description: * Sets the status code of the last event * of types related to the JSON-object. * * Returns: int, the newly set code **/ static int json_set_code( json_obj_t *jobj, int code ) { if ( jobj == NULL ) return jobj->code = JSON_UNINITALIZED_OJB; return jobj->code = code; } /** * Function: json_get_type * Author: Joachim M. Giæver * * Parameters: * - void *entry: The JSON-entry to read type of * * Description: * Returns the type of the JSON-entry. * * Returns: json_types_t, the type **/ static json_types_t json_get_type( void *entry ) { json_type_t *type = (json_type_t *)entry; return type->type; } /** * Function: json_is_type * Author: Joachim M. Giæver * * Parameters: * - void *entry: The JSON-entry to check * - json_types_t: The JSON-type compare against * * Description: * Checks the equality of the type of the entry * agains the given type. * * Returns: int, 1 on success, 0 on failure **/ static int json_is_type( void *entry, json_types_t jtype ) { return json_get_type( entry ) == jtype; } /** * Function: json_uninit_obj * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: The JSON-object (parent of obj) * - void *obj: Any kind of object within parent * * Description: * Checks if the JSON-object is uninitialized. Checks * both the root (jobj) and sub obj. * * Returns: int, 1 on failure, 0 on success **/ static int json_uninit_obj( json_obj_t *jobj, void *obj ) { if ( json_has_err( jobj ) ) return 0; if ( obj == NULL ) { json_set_code( jobj, JSON_UNINITALIZED_OJB ); return 1; } return 0; } /** * Function: json_val_vtype * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: Parent JSON-object * - json_types_t *vtype: The value type * * Description: * Checks if the given type is valid as a value, for * the value entry. * * Returns: int, 1 on success, 0 on failure **/ static int json_val_vtype( json_obj_t *jobj, json_types_t vtype ) { int i; json_types_t val_types[7] = { JSON_OBJ, JSON_ARR, JSON_CHAR, JSON_INT, JSON_FLOAT, JSON_BOOL, JSON_NULL }; for ( i = 0; i < sizeof( val_types ); i++ ) { if ( vtype == val_types[ i ] ) return ( jobj == NULL ? JSON_INS_TYPE_VAL : json_set_code( jobj, JSON_INS_TYPE_VAL ) ); } return ( jobj == NULL ? JSON_INVALID_VAL_TYPE : json_set_code( jobj, JSON_INVALID_VAL_TYPE ) ); } /** * Function: json_insert * Author: Joachim M. Giæver * * Parameters: * - json_obj_t *jobj: Parent JSON-obj * - void *root: Root-entry, an JSON-entry * - void *entry: New entry, valid for root-entry * * Description: * Inserts an entry into the root, which is related * to the parent JSON-obj. Insertion method and possibilities * depends on the root-entry. * * Returns: void *, address to newly inserte entry **/ static void *json_insert( json_obj_t *jobj, void *root, void *entry ) { void *tmp; if ( json_has_err( jobj ) ) return NULL; switch( json_get_type( root ) ) { case JSON_OBJ: if ( !json_is_type( entry, JSON_MEM ) ) { json_set_code( jobj, JSON_INVALID_OBJ_ENT ); return NULL; } tmp = ((json_obj_t *)root)->members; while( tmp != NULL && ((json_mem_t *)tmp)->next != NULL ) tmp = ((json_mem_t *)tmp)->next; if ( tmp == NULL ) ((json_obj_t *)root)->members = (json_mem_t *)entry; else ((json_mem_t *)tmp)->next = (json_mem_t *)entry; json_set_code( jobj, JSON_INS_MEM_OBJ ); break; case JSON_MEM: switch( json_get_type( entry ) ) { case JSON_PAIR: case JSON_MEM: tmp = ((json_mem_t *)root)->entry; if ( tmp == NULL ) ((json_mem_t *)root)->entry = entry; while( tmp != NULL && ( ( json_is_type( entry, JSON_MEM ) && ((json_mem_t *)tmp)->next != NULL ) || ( json_is_type( entry, JSON_PAIR ) && ((json_pair_t *)tmp)->next != NULL ) ) ) { tmp = ( json_is_type( entry, JSON_MEM ) ? ((json_mem_t *)tmp)->next : ((json_pair_t *)tmp)->next ); } if ( tmp != NULL ) { if ( json_is_type( entry, JSON_MEM ) ) ((json_mem_t *)tmp)->next = entry; else ((json_pair_t *)tmp)->next = entry; } json_set_code( jobj, JSON_INS_PAIR_MEM ); break; default: json_set_code( jobj, JSON_INVALID_MEM_ENT ); break; } break; case JSON_PAIR: if ( !json_is_type( entry, JSON_VAL ) ) { json_set_code( jobj, JSON_INVALID_PAIR_ENT ); return NULL; } ((json_pair_t *)root)->value = entry; json_set_code( jobj, JSON_INS_VAL_PAIR ); break; case JSON_ELEM: if ( !json_is_type( entry, JSON_VAL ) ) { json_set_code( jobj, JSON_INVALID_ELEM_ENT ); break; } tmp = ((json_elem_t *)root)->entry; if ( tmp != NULL ) json_destroy_value( tmp ); ((json_elem_t *)root)->entry = entry; json_set_code( jobj, JSON_INS_VAL_ELEM ); break; case JSON_ARR: if ( !json_is_type( entry, JSON_ELEM ) ) { json_set_code( jobj, JSON_INVALID_ARR_ENT ); return NULL; } tmp = ((json_arr_t *)root)->entry; if ( tmp == NULL ) ((json_arr_t *)root)->entry = entry; else { while( tmp != NULL && ((json_elem_t *)tmp)->next != NULL ) tmp = ((json_elem_t *)tmp)->next; ((json_elem_t *)tmp)->next = entry; } json_set_code( jobj, JSON_INS_ELEM_ARR ); break; case JSON_VAL: switch( json_get_type( entry ) ) { case JSON_OBJ: case JSON_ARR: ((json_val_t *)root)->value = entry; json_set_code( jobj, JSON_INS_VAL_VAL ); break; default: json_set_code( jobj, JSON_INVALID_VAL_ENT ); return NULL; } break; default: json_set_code( jobj, JSON_INVALID_ROOT_ENT ); return NULL; } return entry; } /** Recursice functions to print the tree **/ static void _json_out( json_obj_t *jobj, int height ) { if ( jobj == NULL ) return; _print_mem( jobj, jobj->members, height ); } static void _print_( json_obj_t *jobj, ... ) { va_list vargs; char *format; va_start( vargs, jobj ); if ( jobj->jfile == NULL || (jobj->ptype & JSON_PRINT) == JSON_PRINT ) { format = va_arg( vargs, char * ); vprintf( format, vargs ); } va_end( vargs ); } static void _print_mem( json_obj_t *jobj, json_mem_t *jmem, int height ) { char *tabs; if ( jmem == NULL ) return; tabs = _print_tabs( jobj, height ); _print_( jobj, "%s{%s", tabs, _print_set_newline( jobj ) ); if ( json_is_type( jmem->entry, JSON_PAIR ) ) _print_pair( jobj, jmem->entry, height + 1 ); else _print_mem( jobj, jmem->entry, height + 1 ); _print_( jobj, "%s}%s%s", tabs, ( jmem->next != NULL ? "," : "" ), _print_set_newline( jobj ) ); _print_tabs_release( tabs ); _print_mem( jobj, jmem->next, height ); } static void _print_pair( json_obj_t *jobj, json_pair_t *jpair, int height ) { char *tabs; if ( jpair == NULL ) return; tabs = _print_tabs( jobj, height ); _print_( jobj, "%s\"%s\":", tabs, jpair->str ); _print_value( jobj, jpair->value, height + 1 ); _print_( jobj, "%s%s", ( jpair->next != NULL ? "," : "" ), _print_set_newline( jobj ) ); _print_tabs_release( tabs ); if ( jpair->next != NULL ) { if ( json_is_type( jpair->next, JSON_PAIR ) ) _print_pair( jobj, jpair->next, height ); else if ( json_is_type( jpair->next, JSON_MEM ) ) _print_mem( jobj, jpair->next, height ); } } static void _print_arr( json_obj_t *jobj, json_arr_t *jarr, int height ) { char *tabs; if ( jarr == NULL ) return; tabs = _print_tabs( jobj, height - 1 ); _print_( jobj, "[%s", _print_set_newline( jobj ) ); _print_elem( jobj, jarr->entry, height ); _print_( jobj, "%s]", tabs ); _print_tabs_release( tabs ); } static void _print_elem( json_obj_t *jobj, json_elem_t *jelem, int height ) { char *tabs; if ( jelem == NULL ) return; tabs = _print_tabs( jobj, height ); _print_( jobj, "%s", tabs ); _print_value( jobj, jelem->entry, height ); _print_( jobj, "%s%s", ( jelem->next != NULL ? "," : "" ), _print_set_newline( jobj ) ); _print_elem( jobj, jelem->next, height ); _print_tabs_release( tabs ); } static void _print_value( json_obj_t *jobj, json_val_t *jval, int height ) { char *tabs; if ( jval == NULL ) { _print_( jobj, "\"\"" ); return; } tabs = _print_tabs( jobj, height + 1 ); switch( jval->sub_type ) { case JSON_OBJ: _json_out( jval->value, height ); break; case JSON_ARR: _print_arr( jobj, jval->value, height ); break; case JSON_CHAR: case JSON_BOOL: case JSON_NULL: _print_( jobj, "\"%s\"", (char *)jval->value ); break; case JSON_INT: _print_( jobj, "%d", *(int *)jval->value ); break; case JSON_FLOAT: _print_( jobj, "%f", *(float *)jval->value ); break; default: _print_( jobj, "\"\""); break; } _print_tabs_release( tabs ); } static char *_print_set_newline( json_obj_t *jobj ) { return (jobj->ptype & JSON_PPRINT) == JSON_PPRINT ? "\n": ""; } static void _print_tabs_release( char *tabs ) { if ( tabs == NULL ) return; free( tabs ); } static char *_print_tabs( json_obj_t *jobj, int height ) { int i; char *tabs; if ( (jobj->ptype & JSON_PPRINT) == JSON_PPRINT ) { tabs = ( char *) malloc( sizeof( char * ) ); tabs[0] = 0; return tabs; } tabs = ( char *) malloc( sizeof( char * ) * height ); for ( i = 0; i < height; i++ ) tabs[ i ] = '\t'; tabs[i] = 0; return tabs; } /** Silence in comments is like nothing was here */ /*** * THIS IS FOR DEBUGGING OF THE JSON-IMPLEMENTATION; * To run this make project as: * $ make json-test * and run by * $ ./json-test **/ #ifdef _DEBUG_JSON int main(int argc, char const *argv[]) { int i = 18848; float f = 154.4848; bool b = true; json_obj_t *jobj = json_create( "", JSON_PRINT | JSON_PPRINT ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_mem_t *jmem = json_create_mem( jobj ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_pair_t *jpair = json_create_pair( jobj, jmem, "Test" ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_pair_t *jpair2 = json_create_pair( jobj, jmem, "Test" ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_pair_t *jpair3 = json_create_pair( jobj, jmem, "Test" ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_val_t *jval = json_insert_value( jobj, jpair, JSON_CHAR, "Litt text" ); jval = json_insert_value( jobj, jpair2, JSON_CHAR, "Litt mer test" ); jval = json_insert_value( jobj, jpair3, JSON_CHAR, "Litt test" ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_mem_t *jmem2 = json_create_mem( jobj ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); jpair2 = json_create_pair( jobj, jmem2, "array" ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_val_t *jval2 = json_insert_value( jobj, jpair2, JSON_ARR, NULL ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_arr_t *jarr = json_create_arr( jobj, jval2 ); if ( json_has_err( jobj ) ) printf("ERR: %s\n\n", json_last_errmsg( jobj ) ); json_elem_t *elem = json_create_elem( jobj, jarr ); json_val_t *val = json_insert_value( jobj, elem, JSON_INT, &i ); elem = json_create_elem( jobj, jarr ); val = json_insert_value( jobj, elem, JSON_BOOL, &b ); elem = json_create_elem( jobj, jarr ); val = json_insert_value( jobj, elem, JSON_CHAR, "FUCK YOU" ); elem = json_create_elem( jobj, jarr ); val = json_insert_value( jobj, elem, JSON_FLOAT, &f ); elem = json_create_elem( jobj, jarr ); val = json_insert_value( jobj, elem, JSON_NULL, NULL ); json_out( jobj ); json_destroy( jobj ); return EXIT_SUCCESS; } #endif