diff --git a/json_util.c b/json_util.c index d7351dd..9a2f9ff 100644 --- a/json_util.c +++ b/json_util.c @@ -65,6 +65,8 @@ static int sscanf_is_broken = 0; static int sscanf_is_broken_testdone = 0; static void sscanf_is_broken_test(void); +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); + static char _last_err[256] = ""; const char *json_util_get_last_err() @@ -126,42 +128,61 @@ struct json_object* json_object_from_file(const char *filename) int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) { - const char *json_str; - int fd, ret; - unsigned int wpos, wsize; + int fd, ret; + int saved_errno; - if(!obj) { - _set_last_err("json_object_to_file: object is null\n"); - return -1; - } + if (!obj) { + _set_last_err("json_object_to_file: object is null\n"); + return -1; + } - if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { - _set_last_err("json_object_to_file: error opening file %s: %s\n", - filename, strerror(errno)); - return -1; - } + if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { + _set_last_err("json_object_to_file: error opening file %s: %s\n", + filename, strerror(errno)); + return -1; + } + ret = _json_object_to_fd(fd, obj, flags, filename); + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} - if(!(json_str = json_object_to_json_string_ext(obj,flags))) { - close(fd); - return -1; - } +int json_object_to_fd(int fd, struct json_object *obj, int flags) +{ + if (!obj) { + _set_last_err("json_object_to_fd: object is null\n"); + return -1; + } - wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ - wpos = 0; - while(wpos < wsize) { - if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { - close(fd); - _set_last_err("json_object_to_file: error writing file %s: %s\n", - filename, strerror(errno)); - return -1; - } + return _json_object_to_fd(fd, obj, flags, NULL); +} +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) +{ + int ret; + const char *json_str; + unsigned int wpos, wsize; - /* because of the above check for ret < 0, we can safely cast and add */ - wpos += (unsigned int)ret; - } + filename = filename ? filename : "(fd)"; - close(fd); - return 0; + if (!(json_str = json_object_to_json_string_ext(obj,flags))) { + return -1; + } + + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + wpos = 0; + while(wpos < wsize) { + if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { + _set_last_err("json_object_to_file: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; + } + + return 0; } // backwards compatible "format and write to file" function diff --git a/json_util.h b/json_util.h index a913278..d8926db 100644 --- a/json_util.h +++ b/json_util.h @@ -67,7 +67,18 @@ extern int json_object_to_file(const char *filename, struct json_object *obj); extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); /** - * Return the last error from json_object_to_file{,_ext} or + * Convert the json_object to a string and write it to the file descriptor. + * Handles partial writes and will keep writing until done, or an error + * occurs. + * + * @param flags flags to pass to json_object_to_json_string_ext() + * @return -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_fd(int fd, struct json_object *obj, int flags); + +/** + * Return the last error from json_object_to_file{,_ext}, + * json_object_to_fd() or * json_object_from_{file,fd}, or NULL if there is none. */ const char *json_util_get_last_err(void); diff --git a/tests/test_util_file.c b/tests/test_util_file.c index 1b4b066..f98dce2 100644 --- a/tests/test_util_file.c +++ b/tests/test_util_file.c @@ -49,6 +49,25 @@ static void test_write_to_file() (rv == 0) ? "OK" : "FAIL", outfile2, rv); if (rv == 0) stat_and_cat(outfile2); + + const char *outfile3 = "json3.out"; + int d = open(outfile3, O_WRONLY|O_CREAT, 0600); + if (d < 0) + { + printf("FAIL: unable to open %s %s\n", outfile3, strerror(errno)); + return; + } + rv = json_object_to_fd(d, jso, JSON_C_TO_STRING_PRETTY); + printf("%s: json_object_to_fd(%s, jso, JSON_C_TO_STRING_PRETTY)=%d\n", + (rv == 0) ? "OK" : "FAIL", outfile3, rv); + // Write the same object twice + rv = json_object_to_fd(d, jso, JSON_C_TO_STRING_PLAIN); + printf("%s: json_object_to_fd(%s, jso, JSON_C_TO_STRING_PLAIN)=%d\n", + (rv == 0) ? "OK" : "FAIL", outfile3, rv); + close(d); + if (rv == 0) + stat_and_cat(outfile3); + json_object_put(jso); } diff --git a/tests/test_util_file.expected b/tests/test_util_file.expected index 09121b9..f64a5a5 100644 --- a/tests/test_util_file.expected +++ b/tests/test_util_file.expected @@ -19,3 +19,17 @@ file[json2.out], size=367, contents={ "foo8":"abcdefghijklmnopqrstuvwxyz", "foo9":"abcdefghijklmnopqrstuvwxyz" } +OK: json_object_to_fd(json3.out, jso, JSON_C_TO_STRING_PRETTY)=0 +OK: json_object_to_fd(json3.out, jso, JSON_C_TO_STRING_PLAIN)=0 +file[json3.out], size=703, contents={ + "foo":1234, + "foo1":"abcdefghijklmnopqrstuvwxyz", + "foo2":"abcdefghijklmnopqrstuvwxyz", + "foo3":"abcdefghijklmnopqrstuvwxyz", + "foo4":"abcdefghijklmnopqrstuvwxyz", + "foo5":"abcdefghijklmnopqrstuvwxyz", + "foo6":"abcdefghijklmnopqrstuvwxyz", + "foo7":"abcdefghijklmnopqrstuvwxyz", + "foo8":"abcdefghijklmnopqrstuvwxyz", + "foo9":"abcdefghijklmnopqrstuvwxyz" +}{"foo":1234,"foo1":"abcdefghijklmnopqrstuvwxyz","foo2":"abcdefghijklmnopqrstuvwxyz","foo3":"abcdefghijklmnopqrstuvwxyz","foo4":"abcdefghijklmnopqrstuvwxyz","foo5":"abcdefghijklmnopqrstuvwxyz","foo6":"abcdefghijklmnopqrstuvwxyz","foo7":"abcdefghijklmnopqrstuvwxyz","foo8":"abcdefghijklmnopqrstuvwxyz","foo9":"abcdefghijklmnopqrstuvwxyz"}