There are now three options: JSON_C_TO_STRING_SPACED, JSON_C_TO_STRING_PLAIN and JSON_C_TO_STRING_PRETTY. This also add a json_object_to_file_ext() that takes the same flags. Existing output of json_object_to_json_string() is unchanged, and uses JSON_C_TO_STRING_SPACED. Thanks fo Grant Edwards for the initial patches.tags/json-c-0.10-20120530
@@ -180,45 +180,88 @@ enum json_type json_object_get_type(struct json_object *jso) | |||||
return jso->o_type; | return jso->o_type; | ||||
} | } | ||||
/* json_object_to_json_string */ | |||||
/* extended conversion to string */ | |||||
const char* json_object_to_json_string_ext(struct json_object *jso, int flags) | |||||
{ | |||||
if (!jso) | |||||
return "null"; | |||||
if ((!jso->_pb) && !(jso->_pb = printbuf_new())) | |||||
return NULL; | |||||
printbuf_reset(jso->_pb); | |||||
if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0) | |||||
return NULL; | |||||
return jso->_pb->buf; | |||||
} | |||||
/* backwards-compatible conversion to string */ | |||||
const char* json_object_to_json_string(struct json_object *jso) | const char* json_object_to_json_string(struct json_object *jso) | ||||
{ | { | ||||
if(!jso) return "null"; | |||||
if(!jso->_pb) { | |||||
if(!(jso->_pb = printbuf_new())) return NULL; | |||||
} else { | |||||
printbuf_reset(jso->_pb); | |||||
} | |||||
if(jso->_to_json_string(jso, jso->_pb) < 0) return NULL; | |||||
return jso->_pb->buf; | |||||
return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); | |||||
} | } | ||||
static void indent(struct printbuf *pb, int level, int flags) | |||||
{ | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
{ | |||||
printbuf_memset(pb, -1, ' ', level * 2); | |||||
} | |||||
} | |||||
/* json_object_object */ | /* json_object_object */ | ||||
static int json_object_object_to_json_string(struct json_object* jso, | static int json_object_object_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
{ | |||||
int i=0; | |||||
struct json_object_iter iter; | |||||
sprintbuf(pb, "{"); | |||||
/* CAW: scope operator to make ANSI correctness */ | |||||
/* CAW: switched to json_object_object_foreachC which uses an iterator struct */ | |||||
json_object_object_foreachC(jso, iter) { | |||||
if(i) sprintbuf(pb, ","); | |||||
sprintbuf(pb, " \""); | |||||
json_escape_str(pb, iter.key, strlen(iter.key)); | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | |||||
int had_children = 0; | |||||
struct json_object_iter iter; | |||||
sprintbuf(pb, "{" /*}*/); | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
sprintbuf(pb, "\n"); | |||||
json_object_object_foreachC(jso, iter) | |||||
{ | |||||
if (had_children) | |||||
{ | |||||
sprintbuf(pb, ","); | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
sprintbuf(pb, "\n"); | |||||
} | |||||
had_children = 1; | |||||
if (flags & JSON_C_TO_STRING_SPACED) | |||||
sprintbuf(pb, " "); | |||||
indent(pb, level+1, flags); | |||||
sprintbuf(pb, "\""); | |||||
json_escape_str(pb, iter.key, strlen(iter.key)); | |||||
if (flags & JSON_C_TO_STRING_SPACED) | |||||
sprintbuf(pb, "\": "); | sprintbuf(pb, "\": "); | ||||
if(iter.val == NULL) sprintbuf(pb, "null"); | |||||
else iter.val->_to_json_string(iter.val, pb); | |||||
i++; | |||||
else | |||||
sprintbuf(pb, "\":"); | |||||
if(iter.val == NULL) | |||||
sprintbuf(pb, "null"); | |||||
else | |||||
iter.val->_to_json_string(iter.val, pb, level+1,flags); | |||||
} | } | ||||
return sprintbuf(pb, " }"); | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
{ | |||||
if (had_children) | |||||
sprintbuf(pb, "\n"); | |||||
indent(pb,level,flags); | |||||
} | |||||
if (flags & JSON_C_TO_STRING_SPACED) | |||||
return sprintbuf(pb, /*{*/ " }"); | |||||
else | |||||
return sprintbuf(pb, /*{*/ "}"); | |||||
} | } | ||||
static void json_object_lh_entry_free(struct lh_entry *ent) | static void json_object_lh_entry_free(struct lh_entry *ent) | ||||
{ | { | ||||
free(ent->k); | free(ent->k); | ||||
@@ -291,7 +334,9 @@ void json_object_object_del(struct json_object* jso, const char *key) | |||||
/* json_object_boolean */ | /* json_object_boolean */ | ||||
static int json_object_boolean_to_json_string(struct json_object* jso, | static int json_object_boolean_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | { | ||||
if(jso->o.c_boolean) return sprintbuf(pb, "true"); | if(jso->o.c_boolean) return sprintbuf(pb, "true"); | ||||
else return sprintbuf(pb, "false"); | else return sprintbuf(pb, "false"); | ||||
@@ -327,7 +372,9 @@ json_bool json_object_get_boolean(struct json_object *jso) | |||||
/* json_object_int */ | /* json_object_int */ | ||||
static int json_object_int_to_json_string(struct json_object* jso, | static int json_object_int_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | { | ||||
return sprintbuf(pb, "%"PRId64, jso->o.c_int64); | return sprintbuf(pb, "%"PRId64, jso->o.c_int64); | ||||
} | } | ||||
@@ -412,7 +459,9 @@ int64_t json_object_get_int64(struct json_object *jso) | |||||
/* json_object_double */ | /* json_object_double */ | ||||
static int json_object_double_to_json_string(struct json_object* jso, | static int json_object_double_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | { | ||||
return sprintbuf(pb, "%lf", jso->o.c_double); | return sprintbuf(pb, "%lf", jso->o.c_double); | ||||
} | } | ||||
@@ -449,7 +498,9 @@ double json_object_get_double(struct json_object *jso) | |||||
/* json_object_string */ | /* json_object_string */ | ||||
static int json_object_string_to_json_string(struct json_object* jso, | static int json_object_string_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | { | ||||
sprintbuf(pb, "\""); | sprintbuf(pb, "\""); | ||||
json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); | json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len); | ||||
@@ -511,20 +562,45 @@ int json_object_get_string_len(struct json_object *jso) { | |||||
/* json_object_array */ | /* json_object_array */ | ||||
static int json_object_array_to_json_string(struct json_object* jso, | static int json_object_array_to_json_string(struct json_object* jso, | ||||
struct printbuf *pb) | |||||
{ | |||||
int i; | |||||
sprintbuf(pb, "["); | |||||
for(i=0; i < json_object_array_length(jso); i++) { | |||||
struct json_object *val; | |||||
if(i) { sprintbuf(pb, ", "); } | |||||
else { sprintbuf(pb, " "); } | |||||
val = json_object_array_get_idx(jso, i); | |||||
if(val == NULL) { sprintbuf(pb, "null"); } | |||||
else { val->_to_json_string(val, pb); } | |||||
} | |||||
return sprintbuf(pb, " ]"); | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags) | |||||
{ | |||||
int had_children = 0; | |||||
int ii; | |||||
sprintbuf(pb, "["); | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
sprintbuf(pb, "\n"); | |||||
for(ii=0; ii < json_object_array_length(jso); ii++) | |||||
{ | |||||
struct json_object *val; | |||||
if (had_children) | |||||
{ | |||||
sprintbuf(pb, ","); | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
sprintbuf(pb, "\n"); | |||||
} | |||||
had_children = 1; | |||||
if (flags & JSON_C_TO_STRING_SPACED) | |||||
sprintbuf(pb, " "); | |||||
indent(pb, level + 1, flags); | |||||
val = json_object_array_get_idx(jso, ii); | |||||
if(val == NULL) | |||||
sprintbuf(pb, "null"); | |||||
else | |||||
val->_to_json_string(val, pb, level+1, flags); | |||||
} | |||||
if (flags & JSON_C_TO_STRING_PRETTY) | |||||
{ | |||||
if (had_children) | |||||
sprintbuf(pb, "\n"); | |||||
indent(pb,level,flags); | |||||
} | |||||
if (flags & JSON_C_TO_STRING_SPACED) | |||||
return sprintbuf(pb, " ]"); | |||||
else | |||||
return sprintbuf(pb, "]"); | |||||
} | } | ||||
static void json_object_array_entry_free(void *data) | static void json_object_array_entry_free(void *data) | ||||
@@ -21,6 +21,28 @@ extern "C" { | |||||
#define JSON_OBJECT_DEF_HASH_ENTRIES 16 | #define JSON_OBJECT_DEF_HASH_ENTRIES 16 | ||||
/** | |||||
* A flag for the json_object_to_json_string_ext() and | |||||
* json_object_to_file_ext() functions which causes the output | |||||
* to have no extra whitespace or formatting applied. | |||||
*/ | |||||
#define JSON_C_TO_STRING_PLAIN 0 | |||||
/** | |||||
* A flag for the json_object_to_json_string_ext() and | |||||
* json_object_to_file_ext() functions which causes the output to have | |||||
* minimal whitespace inserted to make things slightly more readable. | |||||
*/ | |||||
#define JSON_C_TO_STRING_SPACED (1<<0) | |||||
/** | |||||
* A flag for the json_object_to_json_string_ext() and | |||||
* json_object_to_file_ext() functions which causes | |||||
* the output to be formatted. | |||||
* | |||||
* See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ | |||||
* for an example of the format. | |||||
*/ | |||||
#define JSON_C_TO_STRING_PRETTY (1<<1) | |||||
#undef FALSE | #undef FALSE | ||||
#define FALSE ((json_bool)0) | #define FALSE ((json_bool)0) | ||||
@@ -112,12 +134,21 @@ extern int json_object_is_type(struct json_object *obj, enum json_type type); | |||||
extern enum json_type json_object_get_type(struct json_object *obj); | extern enum json_type json_object_get_type(struct json_object *obj); | ||||
/** Stringify object to json format | |||||
/** Stringify object to json format. | |||||
* Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) | |||||
* @param obj the json_object instance | * @param obj the json_object instance | ||||
* @returns a string in JSON format | * @returns a string in JSON format | ||||
*/ | */ | ||||
extern const char* json_object_to_json_string(struct json_object *obj); | extern const char* json_object_to_json_string(struct json_object *obj); | ||||
/** Stringify object to json format | |||||
* @param obj the json_object instance | |||||
* @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants | |||||
* @returns a string in JSON format | |||||
*/ | |||||
extern const char* json_object_to_json_string_ext(struct json_object *obj, int | |||||
flags); | |||||
/* object type methods */ | /* object type methods */ | ||||
@@ -18,7 +18,9 @@ extern "C" { | |||||
typedef void (json_object_delete_fn)(struct json_object *o); | typedef void (json_object_delete_fn)(struct json_object *o); | ||||
typedef int (json_object_to_json_string_fn)(struct json_object *o, | typedef int (json_object_to_json_string_fn)(struct json_object *o, | ||||
struct printbuf *pb); | |||||
struct printbuf *pb, | |||||
int level, | |||||
int flags); | |||||
struct json_object | struct json_object | ||||
{ | { | ||||
@@ -65,12 +65,12 @@ struct json_object* json_object_from_file(const char *filename) | |||||
if((fd = open(filename, O_RDONLY)) < 0) { | if((fd = open(filename, O_RDONLY)) < 0) { | ||||
MC_ERROR("json_object_from_file: error reading file %s: %s\n", | MC_ERROR("json_object_from_file: error reading file %s: %s\n", | ||||
filename, strerror(errno)); | filename, strerror(errno)); | ||||
return (struct json_object*)error_ptr(-1); | |||||
return NULL; // XAX this is an API change! | |||||
} | } | ||||
if(!(pb = printbuf_new())) { | if(!(pb = printbuf_new())) { | ||||
close(fd); | close(fd); | ||||
MC_ERROR("json_object_from_file: printbuf_new failed\n"); | MC_ERROR("json_object_from_file: printbuf_new failed\n"); | ||||
return (struct json_object*)error_ptr(-1); | |||||
return NULL; | |||||
} | } | ||||
while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { | while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { | ||||
printbuf_memappend(pb, buf, ret); | printbuf_memappend(pb, buf, ret); | ||||
@@ -80,14 +80,16 @@ struct json_object* json_object_from_file(const char *filename) | |||||
MC_ABORT("json_object_from_file: error reading file %s: %s\n", | MC_ABORT("json_object_from_file: error reading file %s: %s\n", | ||||
filename, strerror(errno)); | filename, strerror(errno)); | ||||
printbuf_free(pb); | printbuf_free(pb); | ||||
return (struct json_object*)error_ptr(-1); | |||||
return NULL; | |||||
} | } | ||||
obj = json_tokener_parse(pb->buf); | obj = json_tokener_parse(pb->buf); | ||||
printbuf_free(pb); | printbuf_free(pb); | ||||
return obj; | return obj; | ||||
} | } | ||||
int json_object_to_file(char *filename, struct json_object *obj) | |||||
/* extended "format and write to file" function */ | |||||
int json_object_to_file_ext(char *filename, struct json_object *obj, int flags) | |||||
{ | { | ||||
const char *json_str; | const char *json_str; | ||||
int fd, ret; | int fd, ret; | ||||
@@ -104,7 +106,7 @@ int json_object_to_file(char *filename, struct json_object *obj) | |||||
return -1; | return -1; | ||||
} | } | ||||
if(!(json_str = json_object_to_json_string(obj))) { | |||||
if(!(json_str = json_object_to_json_string_ext(obj,flags))) { | |||||
close(fd); | close(fd); | ||||
return -1; | return -1; | ||||
} | } | ||||
@@ -127,6 +129,13 @@ int json_object_to_file(char *filename, struct json_object *obj) | |||||
return 0; | return 0; | ||||
} | } | ||||
// backwards compatible "format and write to file" function | |||||
int json_object_to_file(char *filename, struct json_object *obj) | |||||
{ | |||||
return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); | |||||
} | |||||
int json_parse_int64(const char *buf, int64_t *retval) | int json_parse_int64(const char *buf, int64_t *retval) | ||||
{ | { | ||||
int64_t num64; | int64_t num64; | ||||
@@ -23,8 +23,10 @@ extern "C" { | |||||
/* utility functions */ | /* utility functions */ | ||||
extern struct json_object* json_object_from_file(const char *filename); | extern struct json_object* json_object_from_file(const char *filename); | ||||
extern int json_object_to_file(char *filename, struct json_object *obj); | extern int json_object_to_file(char *filename, struct json_object *obj); | ||||
extern int json_object_to_file_ext(char *filename, struct json_object *obj, int flags); | |||||
extern int json_parse_int64(const char *buf, int64_t *retval); | extern int json_parse_int64(const char *buf, int64_t *retval); | ||||
/** | /** | ||||
* Return a string describing the type of the object. | * Return a string describing the type of the object. | ||||
* e.g. "int", or "object", etc... | * e.g. "int", or "object", etc... | ||||