From 3fcffe1bb01de6978f4516abd49a3b3c9e2cd2f2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 28 Apr 2012 13:26:09 -0500 Subject: [PATCH] Add a json_object_to_json_string_ext() function to allow the formatting of output to be selected. 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. --- json_object.c | 164 ++++++++++++++++++++++++++++++------------ json_object.h | 33 ++++++++- json_object_private.h | 4 +- json_util.c | 19 +++-- json_util.h | 2 + 5 files changed, 171 insertions(+), 51 deletions(-) diff --git a/json_object.c b/json_object.c index 84af414..825630f 100644 --- a/json_object.c +++ b/json_object.c @@ -180,45 +180,88 @@ enum json_type json_object_get_type(struct json_object *jso) 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) { - 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 */ 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, "\": "); - 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) { free(ent->k); @@ -291,7 +334,9 @@ void json_object_object_del(struct json_object* jso, const char *key) /* json_object_boolean */ 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"); else return sprintbuf(pb, "false"); @@ -327,7 +372,9 @@ json_bool json_object_get_boolean(struct json_object *jso) /* json_object_int */ 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); } @@ -412,7 +459,9 @@ int64_t json_object_get_int64(struct json_object *jso) /* json_object_double */ 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); } @@ -449,7 +498,9 @@ double json_object_get_double(struct json_object *jso) /* json_object_string */ static int json_object_string_to_json_string(struct json_object* jso, - struct printbuf *pb) + struct printbuf *pb, + int level, + int flags) { sprintbuf(pb, "\""); 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 */ 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) diff --git a/json_object.h b/json_object.h index f7ec9ea..6520a9a 100644 --- a/json_object.h +++ b/json_object.h @@ -21,6 +21,28 @@ extern "C" { #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 #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); -/** 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 * @returns a string in JSON format */ 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 */ diff --git a/json_object_private.h b/json_object_private.h index 112ce76..597332b 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -18,7 +18,9 @@ extern "C" { typedef void (json_object_delete_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 { diff --git a/json_util.c b/json_util.c index c6db882..e551d2d 100644 --- a/json_util.c +++ b/json_util.c @@ -65,12 +65,12 @@ struct json_object* json_object_from_file(const char *filename) if((fd = open(filename, O_RDONLY)) < 0) { MC_ERROR("json_object_from_file: error reading file %s: %s\n", filename, strerror(errno)); - return (struct json_object*)error_ptr(-1); + return NULL; // XAX this is an API change! } if(!(pb = printbuf_new())) { close(fd); 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) { 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", filename, strerror(errno)); printbuf_free(pb); - return (struct json_object*)error_ptr(-1); + return NULL; } obj = json_tokener_parse(pb->buf); printbuf_free(pb); 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; int fd, ret; @@ -104,7 +106,7 @@ int json_object_to_file(char *filename, struct json_object *obj) return -1; } - if(!(json_str = json_object_to_json_string(obj))) { + if(!(json_str = json_object_to_json_string_ext(obj,flags))) { close(fd); return -1; } @@ -127,6 +129,13 @@ int json_object_to_file(char *filename, struct json_object *obj) 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) { int64_t num64; diff --git a/json_util.h b/json_util.h index a77305e..277c3a7 100644 --- a/json_util.h +++ b/json_util.h @@ -23,8 +23,10 @@ extern "C" { /* utility functions */ 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_ext(char *filename, struct json_object *obj, int flags); extern int json_parse_int64(const char *buf, int64_t *retval); + /** * Return a string describing the type of the object. * e.g. "int", or "object", etc...