@@ -75,6 +75,7 @@ struct incomplete_property_str
7575{
7676 char * i_key ; // The key of the current incomplete element.
7777 char * i_state ; // How much of the JSON stringtifying process is done for the incomplete data.
78+ bool set_comma ; // Determines whether to set commad when completing an object/array.
7879 enum cjlib_json_datatypes i_type ; // The type of the incompelte object (object or array)
7980 struct cjlib_queue * i_pending_data_q ; // The data that must be stored in the incomplete object (but not expanded yet).
8081 union {
@@ -631,6 +632,9 @@ int cjlib_json_read(struct cjlib_json *restrict dst)
631632 p_value = parse_property_value ((const struct cjlib_json * ) dst , p_name );
632633 if (NULL == p_value ) goto read_err ;
633634
635+ // If the current data is only a 'comma', nothing else, then ignore it.
636+ if (!strcmp (p_value , "," )) goto read_cleanup ;
637+
634638 if (BUILDING_OBJECT (compl_indicator )) {
635639 if (!strcmp (ROOT_PROPERTY_NAME , p_name ) &&
636640 !strcmp (ROOT_PROPERTY_NAME , curr_incomplete_data .i_name )) goto read_cleanup ;
@@ -759,15 +763,19 @@ int cjlib_json_read(struct cjlib_json *restrict dst)
759763 * Otherwise NULL.
760764 */
761765static inline char * wrap_complete_entry (const char * entry_state , char opening_symbol ,
762- char closing_symbol )
766+ char closing_symbol , bool set_comma )
763767{
764- size_t additional_size = 2 ; // The size of {} or [].
768+ size_t additional_size = 3 ; // The size of {} or [] + comma .
765769 size_t wrapped_size = strlen (entry_state ) + additional_size ;
766770
767771 char * wrapped_state = (char * ) malloc (wrapped_size + 1 );
768772 if (NULL == wrapped_state ) return NULL ;
769773
770- (void ) sprintf (wrapped_state , "%c%s%c" , opening_symbol , entry_state , closing_symbol );
774+ if (set_comma ) {
775+ (void ) sprintf (wrapped_state , "%c%s%c," , opening_symbol , entry_state , closing_symbol );
776+ } else {
777+ (void ) sprintf (wrapped_state , "%c%s%c" , opening_symbol , entry_state , closing_symbol );
778+ }
771779
772780 return wrapped_state ;
773781}
@@ -777,11 +785,12 @@ static inline char *wrap_complete_entry(const char *entry_state, char opening_sy
777785 * and produce a string that is in format KEY : DATA,
778786 *
779787 * @param src The data of the field.
788+ * @param set_comma Determines whether to insert a comma or not.
780789 * @return A string representing an entry of the JSON file (Format KEY : DATA,) -> (KEY COLON DATA COMMA) in success,
781790 * otherwise NULL is returned.
782791 */
783792static char * simple_key_value_paired_stringtify
784- (const struct cjlib_json_data * restrict src )
793+ (const struct cjlib_json_data * restrict src , bool set_comma )
785794{
786795 const size_t comma_len = 1 ;
787796 const size_t colon_len = 1 ;
@@ -797,29 +806,53 @@ static char *simple_key_value_paired_stringtify
797806 // LEN(KEY) + LEN(:) + LEN(VALUE) + LEN(,) + LEN("\0")
798807 result = (char * ) malloc (strlen (src -> c_value .c_str ) + comma_len + colon_len + double_quotes_len + 1 );
799808 if (NULL == result ) return NULL ;
800- (void ) sprintf (result , "\"%s\"," , src -> c_value .c_str );
809+ if (set_comma ) {
810+ (void ) sprintf (result , "\"%s\"," , src -> c_value .c_str );
811+ } else {
812+ (void ) sprintf (result , "\"%s\"" , src -> c_value .c_str );
813+ }
801814 break ;
802815 case CJLIB_NUMBER :
803816 digit_num = snprintf (NULL , 0 , "%f" , src -> c_value .c_num );
804817 result = (char * ) malloc (digit_num + comma_len + colon_len + 1 );
805818 if (NULL == result ) return NULL ;
806- (void ) sprintf (result , "%f," , src -> c_value .c_num );
819+
820+ if (set_comma ) {
821+ (void ) sprintf (result , "%f," , src -> c_value .c_num );
822+ } else {
823+ (void ) sprintf (result , "%f" , src -> c_value .c_num );
824+ }
807825 break ;
808826 case CJLIB_BOOLEAN :
809827 if (src -> c_value .c_boolean ) {
810828 result = (char * ) malloc (boolean_true_len + comma_len + colon_len + 1 );
811829 if (NULL == result ) return NULL ;
812- (void ) sprintf (result , "%s," , "true" );
830+
831+ if (set_comma ) {
832+ (void ) sprintf (result , "%s," , "true" );
833+ } else {
834+ (void ) sprintf (result , "%s" , "true" );
835+ }
813836 } else {
814837 result = (char * ) malloc (boolean_false_len + comma_len + colon_len + 1 );
815838 if (NULL == result ) return NULL ;
816- (void ) sprintf (result , "%s," , "false" );
839+
840+ if (set_comma ) {
841+ (void ) sprintf (result , "%s," , "false" );
842+ } else {
843+ (void ) sprintf (result , "%s" , "false" );
844+ }
817845 }
818846 break ;
819847 case CJLIB_NULL :
820848 result = (char * ) malloc (null_len + comma_len + colon_len + 1 );
821849 if (NULL == result ) return NULL ;
822- (void ) sprintf (result , "%s," , "null" );
850+
851+ if (set_comma ) {
852+ (void ) sprintf (result , "%s," , "null" );
853+ } else {
854+ (void ) sprintf (result , "%s" , "null" );
855+ }
823856 break ;
824857 default :
825858 break ;
@@ -853,6 +886,7 @@ static inline int switch_from_incomplete_obj_str_data
853886 struct cjlib_json_data * examine_entry_data = CJLIB_DICT_NODE_DATA (entry );
854887 * dst = (struct incomplete_property_str ) {
855888 .i_key = key_wrapped ,
889+ .set_comma = true,
856890 .i_type = type ,
857891 .i_state = strdup ("" ),
858892 .i_pending_data_q = (struct cjlib_queue * ) malloc (sizeof (struct cjlib_queue ))
@@ -884,6 +918,7 @@ struct cjlib_json_data *entry_data, const char *key)
884918 struct cjlib_json_data * examine_entry_data = entry_data ;
885919 * dst = (struct incomplete_property_str ) {
886920 .i_key = key_wrapped ,
921+ .set_comma = true,
887922 .i_type = type ,
888923 .i_state = strdup ("" ),
889924 .i_pending_data_q = (struct cjlib_queue * ) malloc (sizeof (struct cjlib_queue ))
@@ -924,12 +959,8 @@ static inline int convert_list_to_queue(struct cjlib_queue *restrict dst, const
924959 return 0 ;
925960}
926961
927-
928962const char * cjlib_json_object_stringtify (const cjlib_json_object * src )
929963{
930- /**
931- * TODO - 1. Why some fields don't appear in the stringtifying version? (look type field in the JSON).
932- */
933964 struct incomplete_property_str curr_incomp ; // The currently expanding data.
934965 struct cjlib_stack incomplete_st ; // The stack of incomplete data.
935966
@@ -940,6 +971,8 @@ const char *cjlib_json_object_stringtify(const cjlib_json_object *src)
940971 char * tmp_key = NULL ; // Used to temporary store the key of the complete JSON object/array.
941972 char * value_str = NULL ; // Used to temporary store the strintify data (see default case in the switch below)
942973
974+ bool set_comma_tmp = true; // Helper, to maintain the information about whether to put comma or not on completion (see incomplete_str & on switch below.)
975+
943976 char opening_symbol_obj = CURLY_BRACKETS_OPEN ;
944977 char opening_symbol_arr = SQUARE_BRACKETS_OPEN ;
945978 char closing_symbol_obj = CURLY_BRACKETS_CLOSE ;
@@ -972,16 +1005,16 @@ const char *cjlib_json_object_stringtify(const cjlib_json_object *src)
9721005 tmp_state = curr_incomp .i_state ;
9731006 if (CJLIB_OBJECT == curr_incomp .i_type ) {
9741007 curr_incomp .i_state = incomplete_property_str_expand_state (curr_incomp .i_state , value_str , tmp_key );
975- free (tmp_key );
976- tmp_key = NULL ;
9771008 } else {
9781009 curr_incomp .i_state = incomplete_property_str_expand_state (curr_incomp .i_state , value_str , NULL );
9791010 }
9801011
1012+ free (tmp_key );
9811013 free (value_str );
9821014 free (tmp_state );
9831015 tmp_state = NULL ;
9841016 value_str = NULL ;
1017+ tmp_key = NULL ;
9851018 }
9861019
9871020 while (!cjlib_queue_is_empty (curr_incomp .i_pending_data_q )) {
@@ -997,59 +1030,81 @@ const char *cjlib_json_object_stringtify(const cjlib_json_object *src)
9971030
9981031 switch (examine_entry_data -> c_datatype ) {
9991032 case CJLIB_OBJECT :
1033+ if (cjlib_queue_is_empty (curr_incomp .i_pending_data_q )) set_comma_tmp = false;
1034+
10001035 cjlib_stack_push (& curr_incomp , sizeof (struct incomplete_property_str ),
10011036 & incomplete_st );
10021037
1003- if (CJLIB_ARRAY == curr_incomp .i_type ) examine_entry = examine_entry_data -> c_value .c_obj ;
1038+ if (CJLIB_ARRAY == curr_incomp .i_type ) examine_entry = examine_entry_data -> c_value .c_obj ;
10041039 if (-1 == switch_from_incomplete_obj_str_data (& curr_incomp , CJLIB_OBJECT , examine_entry )) return NULL ;
1040+
1041+ curr_incomp .set_comma = set_comma_tmp ;
10051042
10061043 if (-1 == cjlib_dict_preorder (curr_incomp .i_pending_data_q , curr_incomp .i_data .object )) return NULL ;
10071044 break ;
10081045 case CJLIB_ARRAY :
1046+ if (cjlib_queue_is_empty (curr_incomp .i_pending_data_q )) set_comma_tmp = false;
10091047 cjlib_stack_push (& curr_incomp , sizeof (struct incomplete_property_str ), & incomplete_st );
10101048
10111049 if (-1 == switch_from_incomplete_arr_str_data (& curr_incomp , CJLIB_ARRAY , examine_entry_data ,
10121050 CJLIB_DICT_NODE_KEY (examine_entry ))) return NULL ;
10131051
1052+ curr_incomp .set_comma = set_comma_tmp ;
10141053 convert_list_to_queue (curr_incomp .i_pending_data_q , curr_incomp .i_data .array );
10151054 break ;
10161055 default :
10171056 tmp_state = curr_incomp .i_state ;
10181057
10191058 if (CJLIB_OBJECT == curr_incomp .i_type ) {
1020- value_str = simple_key_value_paired_stringtify (CJLIB_DICT_NODE_DATA (examine_entry ));
1021- tmp_key = wrap_complete_entry (CJLIB_DICT_NODE_KEY (examine_entry ),opening_symbol_str , closing_symbol_str );
1059+ if (cjlib_queue_is_empty (curr_incomp .i_pending_data_q )) {
1060+ value_str = simple_key_value_paired_stringtify (CJLIB_DICT_NODE_DATA (examine_entry ), false);
1061+ } else {
1062+ value_str = simple_key_value_paired_stringtify (CJLIB_DICT_NODE_DATA (examine_entry ), true);
1063+ }
1064+
1065+ tmp_key = wrap_complete_entry (CJLIB_DICT_NODE_KEY (examine_entry ),opening_symbol_str , closing_symbol_str , false);
10221066 curr_incomp .i_state = incomplete_property_str_expand_state (curr_incomp .i_state , value_str ,
10231067 tmp_key );
10241068
10251069 free (tmp_key );
10261070 tmp_key = NULL ;
10271071 } else {
1028- value_str = simple_key_value_paired_stringtify (examine_entry_data );
1072+ if (cjlib_queue_is_empty (curr_incomp .i_pending_data_q )) {
1073+ value_str = simple_key_value_paired_stringtify (examine_entry_data , false);
1074+ } else {
1075+ value_str = simple_key_value_paired_stringtify (examine_entry_data , true);
1076+ }
1077+
10291078 curr_incomp .i_state = incomplete_property_str_expand_state (curr_incomp .i_state , value_str , NULL );
10301079 }
10311080 free (tmp_state );
10321081 free (value_str );
10331082 tmp_state = NULL ;
10341083 value_str = NULL ;
10351084 break ;
1036- }
1085+ }
1086+
1087+ set_comma_tmp = true;
10371088 }
10381089
10391090 opening_symbol = (CJLIB_OBJECT == curr_incomp .i_type )? opening_symbol_obj : opening_symbol_arr ;
10401091 closing_symbol = (CJLIB_OBJECT == curr_incomp .i_type )? closing_symbol_obj : closing_symbol_arr ;
10411092
10421093 if (CJLIB_OBJECT == curr_incomp .i_type || CJLIB_ARRAY == curr_incomp .i_type ) {
10431094 tmp_state = curr_incomp .i_state ;
1044- curr_incomp .i_state = wrap_complete_entry (curr_incomp .i_state , opening_symbol , closing_symbol );
1095+
1096+ if (cjlib_stack_is_empty (& incomplete_st ) || !curr_incomp .set_comma ) {
1097+ curr_incomp .i_state = wrap_complete_entry (curr_incomp .i_state , opening_symbol , closing_symbol , false);
1098+ } else {
1099+ curr_incomp .i_state = wrap_complete_entry (curr_incomp .i_state , opening_symbol , closing_symbol , true);
1100+ }
10451101
10461102 free (tmp_state );
10471103 if (NULL == curr_incomp .i_state ) return NULL ;
10481104 }
10491105
10501106 value_str = curr_incomp .i_state ;
10511107
1052- // TODO - wrap the array/object with the correct {} or [].
10531108 tmp_key = curr_incomp .i_key ;
10541109 // Free the pending queue (there are no more incomplete data for the JSON object/array that were examined).
10551110 free (curr_incomp .i_pending_data_q );
0 commit comments