src/json.c

changeset 1072
c89283cd559b
parent 1067
7799addf475f
child 1075
0cc4b63a0ae0
equal deleted inserted replaced
1071:028cb6d22197 1072:c89283cd559b
32 #include <string.h> 32 #include <string.h>
33 #include <ctype.h> 33 #include <ctype.h>
34 #include <assert.h> 34 #include <assert.h>
35 #include <stdio.h> 35 #include <stdio.h>
36 #include <errno.h> 36 #include <errno.h>
37 #include <inttypes.h>
37 38
38 /* 39 /*
39 * RFC 8259 40 * RFC 8259
40 * https://tools.ietf.org/html/rfc8259 41 * https://tools.ietf.org/html/rfc8259
41 */ 42 */
887 return &cx_json_value_nothing; 888 return &cx_json_value_nothing;
888 } 889 }
889 return value->value.array.array[index]; 890 return value->value.array.array[index];
890 } 891 }
891 892
892 static void *cx_json_iter_current(const void *it) {
893 const CxIterator *iter = it;
894 return *(CxJsonValue**)iter->elem_handle;
895 }
896
897 static bool cx_json_iter_valid(const void *it) {
898 const CxIterator *iter = it;
899 return iter->index < iter->elem_count;
900 }
901
902 static void cx_json_iter_next(void *it) {
903 CxIterator *iter = it;
904 iter->index++;
905 iter->elem_handle = (char *) iter->elem_handle + sizeof(void *);
906 }
907
908 CxIterator cxJsonArrIter(const CxJsonValue *value) { 893 CxIterator cxJsonArrIter(const CxJsonValue *value) {
909 CxIterator iter; 894 return cxIteratorPtr(
910 895 value->value.array.array,
911 iter.index = 0; 896 value->value.array.array_size
912 iter.elem_count = value->value.array.array_size; 897 );
913 iter.src_handle.m = value->value.array.array; 898 }
914 iter.elem_handle = iter.src_handle.m; 899
915 iter.elem_size = sizeof(CxJsonValue*); 900 CxIterator cxJsonObjIter(const CxJsonValue *value) {
916 iter.base.valid = cx_json_iter_valid; 901 return cxIterator(
917 iter.base.current = cx_json_iter_current; 902 value->value.object.values,
918 iter.base.next = cx_json_iter_next; 903 sizeof(CxJsonObjValue),
919 iter.base.remove = false; 904 value->value.object.values_size
920 iter.base.mutating = false; 905 );
921
922 return iter;
923 } 906 }
924 907
925 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) { 908 CxJsonValue *cx_json_obj_get_cxstr(const CxJsonValue *value, cxstring name) {
926 CxJsonObjValue *member = json_find_objvalue(value, name); 909 CxJsonObjValue *member = json_find_objvalue(value, name);
927 if (member == NULL) { 910 if (member == NULL) {
928 return &cx_json_value_nothing; 911 return &cx_json_value_nothing;
929 } else { 912 } else {
930 return member->value; 913 return member->value;
931 } 914 }
932 } 915 }
916
917 static const CxJsonWriter cx_json_writer_default = {
918 false,
919 true,
920 255,
921 false,
922 0,
923 false,
924 0
925 };
926
927 // TODO: add default for pretty printing and add functions to create default structs
928
929
930 int cx_json_write_rec(
931 void *target,
932 const CxJsonValue *value,
933 cx_write_func wfunc,
934 const CxJsonWriter *settings,
935 unsigned int depth
936 ) {
937 // TODO: implement indentation
938
939 // keep track of written items
940 size_t actual = 0, expected = 0;
941
942 // small buffer for number to string conversions
943 char numbuf[32];
944
945 // recursively write the values
946 switch (value->type) {
947 case CX_JSON_OBJECT: {
948 const char *begin_obj = "{\n";
949 if (settings->pretty) {
950 actual += wfunc(begin_obj, 1, 2, target);
951 expected += 2;
952 } else {
953 actual += wfunc(begin_obj, 1, 1, target);
954 expected++;
955 }
956 CxIterator iter = cxJsonObjIter(value);
957 cx_foreach(CxJsonObjValue*, member, iter) {
958 // the name
959 actual += wfunc("\"", 1, 1, target);
960 // TODO: escape the string
961 actual += wfunc(member->name.ptr, 1,
962 member->name.length, target);
963 actual += wfunc("\"", 1, 1, target);
964 const char *obj_name_sep = ": ";
965 if (settings->pretty) {
966 actual += wfunc(obj_name_sep, 1, 2, target);
967 expected += 4 + member->name.length;
968 } else {
969 actual += wfunc(obj_name_sep, 1, 1, target);
970 expected += 3 + member->name.length;
971 }
972
973 // the value
974 if (0 == cx_json_write_rec(
975 target, member->value,
976 wfunc, settings, depth + 1)
977 ) {
978 actual++; // count the nested values as one item
979 }
980 expected++;
981
982 // end of object-value
983 if (iter.index < iter.elem_count - 1) {
984 const char *obj_value_sep = ",\n";
985 if (settings->pretty) {
986 actual += wfunc(obj_value_sep, 1, 2, target);
987 expected += 2;
988 } else {
989 actual += wfunc(obj_value_sep, 1, 1, target);
990 expected++;
991 }
992 } else {
993 if (settings->pretty) {
994 actual += wfunc("\n", 1, 1, target);
995 expected ++;
996 }
997 }
998 }
999 actual += wfunc("}", 1, 1, target);
1000 expected++;
1001 break;
1002 }
1003 case CX_JSON_ARRAY: {
1004 // TODO: implement array wrapping
1005 actual += wfunc("[", 1, 1, target);
1006 expected++;
1007 CxIterator iter = cxJsonArrIter(value);
1008 cx_foreach(CxJsonValue*, element, iter) {
1009 // TODO: pretty printing obj elements vs. primitives
1010 if (0 == cx_json_write_rec(
1011 target, element,
1012 wfunc, settings, depth + 1)
1013 ) {
1014 actual++; // count the nested values as one item
1015 }
1016 expected++;
1017
1018 if (iter.index < iter.elem_count - 1) {
1019 const char *arr_value_sep = ", ";
1020 if (settings->pretty) {
1021 actual += wfunc(arr_value_sep, 1, 2, target);
1022 expected += 2;
1023 } else {
1024 actual += wfunc(arr_value_sep, 1, 1, target);
1025 expected++;
1026 }
1027 }
1028 }
1029 actual += wfunc("]", 1, 1, target);
1030 expected++;
1031 break;
1032 }
1033 case CX_JSON_STRING: {
1034 actual += wfunc("\"", 1, 1, target);
1035 // TODO: escape the string
1036 actual += wfunc(value->value.string.ptr, 1,
1037 value->value.string.length, target);
1038 actual += wfunc("\"", 1, 1, target);
1039 expected += 2 + value->value.string.length;
1040 break;
1041 }
1042 case CX_JSON_NUMBER: {
1043 // TODO: locale bullshit
1044 // TODO: formatting settings
1045 snprintf(numbuf, 32, "%g", value->value.number);
1046 size_t len = strlen(numbuf);
1047 actual += wfunc(numbuf, 1, len, target);
1048 expected += len;
1049 break;
1050 }
1051 case CX_JSON_INTEGER: {
1052 snprintf(numbuf, 32, "%" PRIi64, value->value.integer);
1053 size_t len = strlen(numbuf);
1054 actual += wfunc(numbuf, 1, len, target);
1055 expected += len;
1056 break;
1057 }
1058 case CX_JSON_LITERAL: {
1059 if (value->value.literal == CX_JSON_TRUE) {
1060 actual += wfunc("true", 1, 4, target);
1061 expected += 4;
1062 } else if (value->value.literal == CX_JSON_FALSE) {
1063 actual += wfunc("false", 1, 5, target);
1064 expected += 5;
1065 } else {
1066 actual += wfunc("null", 1, 4, target);
1067 expected += 4;
1068 }
1069 break;
1070 }
1071 case CX_JSON_NOTHING: {
1072 // deliberately supported as an empty string!
1073 // users might want to just write the result
1074 // of a get operation without testing the value
1075 // and therefore this should not blow up
1076 break;
1077 }
1078 default: assert(false); // LCOV_EXCL_LINE
1079 }
1080
1081 return expected != actual;
1082 }
1083
1084 int cxJsonWrite(
1085 void *target,
1086 const CxJsonValue *value,
1087 cx_write_func wfunc,
1088 const CxJsonWriter *settings
1089 ) {
1090 if (settings == NULL) {
1091 settings = &cx_json_writer_default;
1092 }
1093 assert(target != NULL);
1094 assert(value != NULL);
1095 assert(wfunc != NULL);
1096
1097 return cx_json_write_rec(target, value, wfunc, settings, 0);
1098 }

mercurial