942 false, |
942 false, |
943 80 |
943 80 |
944 }; |
944 }; |
945 } |
945 } |
946 |
946 |
|
947 static int cx_json_writer_indent( |
|
948 void *target, |
|
949 cx_write_func wfunc, |
|
950 const CxJsonWriter *settings, |
|
951 unsigned int depth |
|
952 ) { |
|
953 if (depth == 0) return 0; |
|
954 |
|
955 // determine the width and characters to use |
|
956 const char* indent; // for 32 prepared chars |
|
957 size_t width = depth; |
|
958 if (settings->indent_space) { |
|
959 if (settings->indent == 0) return 0; |
|
960 width *= settings->indent; |
|
961 indent = " "; |
|
962 } else { |
|
963 indent = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; |
|
964 } |
|
965 |
|
966 // calculate the number of write calls and write |
|
967 size_t full = width / 32; |
|
968 size_t remaining = width % 32; |
|
969 for (size_t i = 0; i < full; i++) { |
|
970 if (32 != wfunc(indent, 1, 32, target)) return 1; |
|
971 } |
|
972 if (remaining != wfunc(indent, 1, remaining, target)) return 1; |
|
973 |
|
974 return 0; |
|
975 } |
|
976 |
947 |
977 |
948 int cx_json_write_rec( |
978 int cx_json_write_rec( |
949 void *target, |
979 void *target, |
950 const CxJsonValue *value, |
980 const CxJsonValue *value, |
951 cx_write_func wfunc, |
981 cx_write_func wfunc, |
952 const CxJsonWriter *settings, |
982 const CxJsonWriter *settings, |
953 unsigned int depth |
983 unsigned int depth |
954 ) { |
984 ) { |
955 // TODO: implement indentation |
|
956 |
|
957 // keep track of written items |
985 // keep track of written items |
|
986 // the idea is to reduce the number of jumps for error checking |
958 size_t actual = 0, expected = 0; |
987 size_t actual = 0, expected = 0; |
959 |
988 |
960 // small buffer for number to string conversions |
989 // small buffer for number to string conversions |
961 char numbuf[32]; |
990 char numbuf[32]; |
962 |
991 |
969 expected += 2; |
998 expected += 2; |
970 } else { |
999 } else { |
971 actual += wfunc(begin_obj, 1, 1, target); |
1000 actual += wfunc(begin_obj, 1, 1, target); |
972 expected++; |
1001 expected++; |
973 } |
1002 } |
|
1003 depth++; |
974 CxIterator iter = cxJsonObjIter(value); |
1004 CxIterator iter = cxJsonObjIter(value); |
975 cx_foreach(CxJsonObjValue*, member, iter) { |
1005 cx_foreach(CxJsonObjValue*, member, iter) { |
|
1006 // possible indentation |
|
1007 if (settings->pretty) { |
|
1008 if (cx_json_writer_indent(target, wfunc, settings, depth)) return 1; |
|
1009 } |
|
1010 |
976 // the name |
1011 // the name |
977 actual += wfunc("\"", 1, 1, target); |
1012 actual += wfunc("\"", 1, 1, target); |
978 // TODO: escape the string |
1013 // TODO: escape the string |
979 actual += wfunc(member->name.ptr, 1, |
1014 actual += wfunc(member->name.ptr, 1, |
980 member->name.length, target); |
1015 member->name.length, target); |
987 actual += wfunc(obj_name_sep, 1, 1, target); |
1022 actual += wfunc(obj_name_sep, 1, 1, target); |
988 expected += 3 + member->name.length; |
1023 expected += 3 + member->name.length; |
989 } |
1024 } |
990 |
1025 |
991 // the value |
1026 // the value |
992 if (0 == cx_json_write_rec( |
1027 if (cx_json_write_rec(target, member->value, wfunc, settings, depth)) return 1; |
993 target, member->value, |
|
994 wfunc, settings, depth + 1) |
|
995 ) { |
|
996 actual++; // count the nested values as one item |
|
997 } |
|
998 expected++; |
|
999 |
1028 |
1000 // end of object-value |
1029 // end of object-value |
1001 if (iter.index < iter.elem_count - 1) { |
1030 if (iter.index < iter.elem_count - 1) { |
1002 const char *obj_value_sep = ",\n"; |
1031 const char *obj_value_sep = ",\n"; |
1003 if (settings->pretty) { |
1032 if (settings->pretty) { |
1012 actual += wfunc("\n", 1, 1, target); |
1041 actual += wfunc("\n", 1, 1, target); |
1013 expected ++; |
1042 expected ++; |
1014 } |
1043 } |
1015 } |
1044 } |
1016 } |
1045 } |
|
1046 depth--; |
|
1047 if (settings->pretty) { |
|
1048 if (cx_json_writer_indent(target, wfunc, settings, depth)) return 1; |
|
1049 } |
1017 actual += wfunc("}", 1, 1, target); |
1050 actual += wfunc("}", 1, 1, target); |
1018 expected++; |
1051 expected++; |
1019 break; |
1052 break; |
1020 } |
1053 } |
1021 case CX_JSON_ARRAY: { |
1054 case CX_JSON_ARRAY: { |
1022 // TODO: implement array wrapping |
1055 // TODO: implement array wrapping |
1023 actual += wfunc("[", 1, 1, target); |
1056 actual += wfunc("[", 1, 1, target); |
1024 expected++; |
1057 expected++; |
1025 CxIterator iter = cxJsonArrIter(value); |
1058 CxIterator iter = cxJsonArrIter(value); |
1026 cx_foreach(CxJsonValue*, element, iter) { |
1059 cx_foreach(CxJsonValue*, element, iter) { |
1027 // TODO: pretty printing obj elements vs. primitives |
1060 if (cx_json_write_rec( |
1028 if (0 == cx_json_write_rec( |
|
1029 target, element, |
1061 target, element, |
1030 wfunc, settings, depth + 1) |
1062 wfunc, settings, depth) |
1031 ) { |
1063 ) return 1; |
1032 actual++; // count the nested values as one item |
|
1033 } |
|
1034 expected++; |
|
1035 |
1064 |
1036 if (iter.index < iter.elem_count - 1) { |
1065 if (iter.index < iter.elem_count - 1) { |
1037 const char *arr_value_sep = ", "; |
1066 const char *arr_value_sep = ", "; |
1038 if (settings->pretty) { |
1067 if (settings->pretty) { |
1039 actual += wfunc(arr_value_sep, 1, 2, target); |
1068 actual += wfunc(arr_value_sep, 1, 2, target); |