| 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); |