From 42f08911b5ba35dbd0e3dadc0f3785f8fa3a946a Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sat, 7 Mar 2015 14:01:17 +0100 Subject: [PATCH] data: Return the number of bytes that would have been returned. That is, behave as documented, even if the buffer is NULL or otherwise too small. Return size_t instead of an integer. --- src/core/data.c | 39 ++++++++++++++++++++++----------------- src/core/store_json.c | 4 ++-- src/core/store_lookup.c | 2 +- src/include/core/data.h | 6 +++--- t/unit/core/data_test.c | 19 +++++++++++++++++-- t/unit/utils/proto_test.c | 8 ++++---- 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/core/data.c b/src/core/data.c index 9f2b506..914946f 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -681,9 +681,9 @@ sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2) CMP_NULL(d1, d2); - if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0) + if (! sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED)) return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); - if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0) + if (! sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED)) return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); return strcasecmp(d1_str, d2_str); @@ -918,18 +918,18 @@ sdb_data_strlen(const sdb_data_t *datum) return 0; } /* sdb_data_strlen */ -int +size_t sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) { char tmp[sdb_data_strlen(datum) + 1]; char *data = NULL; bool is_null = 0; - int ret = -1; + size_t ret = 0; size_t i, pos; - if ((! datum) || (! buf) || (! buflen)) - return -1; + if (! datum) + return 0; if (datum->type == SDB_TYPE_NULL) { strncpy(buf, "NULL", buflen); @@ -1005,37 +1005,41 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) } else if (datum->type & SDB_TYPE_ARRAY) { ret = 1; - buf[0] = '['; + if (buflen > 0) + buf[0] = '['; for (i = 0; i < datum->data.array.length; ++i) { sdb_data_t v = SDB_DATA_INIT; - int n; - if ((size_t)ret >= buflen - 1) - break; + size_t n; if (ret > 1) { - buf[ret] = ','; - buf[ret + 1] = ' '; + if (buflen > ret + 1) { + buf[ret] = ','; + buf[ret + 1] = ' '; + } ret += 2; } sdb_data_array_get(datum, i, &v); - n = sdb_data_format(&v, buf + ret, buflen - ret, quoted); + if (buflen > ret) + n = sdb_data_format(&v, buf + ret, buflen - ret, quoted); + else + n = sdb_data_format(&v, NULL, 0, quoted); if (n > 0) ret += n; else break; } - if ((size_t)ret < buflen - 1) { + if (buflen > ret + 1) { buf[ret] = ']'; buf[ret + 1] = '\0'; - ++ret; } + ++ret; } if (is_null) { /* never quote NULL */ strncpy(buf, "NULL", buflen); - ret = (int)SDB_MIN(buflen, 4); + ret = 4; } else if (data) { if (quoted == SDB_UNQUOTED) @@ -1045,7 +1049,8 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) else ret = snprintf(buf, buflen, "\"%s\"", data); } - buf[buflen - 1] = '\0'; + if (buflen > 0) + buf[buflen - 1] = '\0'; return ret; } /* sdb_data_format */ diff --git a/src/core/store_json.c b/src/core/store_json.c index f5be745..a772dc3 100644 --- a/src/core/store_json.c +++ b/src/core/store_json.c @@ -119,8 +119,8 @@ json_emit(sdb_store_json_formatter_t *f, sdb_store_obj_t *obj) if (obj->type == SDB_ATTRIBUTE) { char tmp[sdb_data_strlen(&ATTR(obj)->value) + 1]; char val[2 * sizeof(tmp) + 3]; - if (sdb_data_format(&ATTR(obj)->value, tmp, sizeof(tmp), - SDB_DOUBLE_QUOTED) < 0) + if (! sdb_data_format(&ATTR(obj)->value, tmp, sizeof(tmp), + SDB_DOUBLE_QUOTED)) snprintf(tmp, sizeof(tmp), ""); if (tmp[0] == '"') { diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index 5aa6915..2e73780 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -142,7 +142,7 @@ match_regex_value(int op, sdb_data_t *v, sdb_data_t *re) else if (re->type != SDB_TYPE_REGEX) return 0; - if (sdb_data_format(v, value, sizeof(value), SDB_UNQUOTED) < 0) + if (! sdb_data_format(v, value, sizeof(value), SDB_UNQUOTED)) status = 0; else if (! regexec(&re->data.re.regex, value, 0, NULL, 0)) status = 1; diff --git a/src/include/core/data.h b/src/include/core/data.h index c037fb0..e529fb9 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -55,7 +55,8 @@ enum { }; #define SDB_TYPE_TO_STRING(t) \ - (((t) == SDB_TYPE_INTEGER) ? "INTEGER" \ + (((t) == SDB_TYPE_NULL) ? "NULL" \ + : ((t) == SDB_TYPE_INTEGER) ? "INTEGER" \ : ((t) == SDB_TYPE_DECIMAL) ? "DECIMAL" \ : ((t) == SDB_TYPE_STRING) ? "STRING" \ : ((t) == SDB_TYPE_DATETIME) ? "DATETIME" \ @@ -289,9 +290,8 @@ enum { * - the number of characters written to the buffer (excluding the terminated * null byte) or the number of characters which would have been written in * case the output was truncated - * - a negative value else */ -int +size_t sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted); /* diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index 71dae2a..cd76dff 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -2032,6 +2032,10 @@ START_TEST(test_format) sdb_data_t datum; const char *expected; } golden_data[] = { + { + { SDB_TYPE_NULL, { .integer = 0 } }, + "NULL", + }, { { SDB_TYPE_INTEGER, { .integer = 4711 } }, "4711", @@ -2100,10 +2104,11 @@ START_TEST(test_format) for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { sdb_data_t *datum = &golden_data[i].datum; char buf[sdb_data_strlen(datum) + 2]; - int check; + size_t check_null, check; memset(buf, (int)'A', sizeof(buf)); + check_null = sdb_data_format(datum, NULL, 0, SDB_DOUBLE_QUOTED); check = sdb_data_format(datum, buf, sizeof(buf) - 1, SDB_DOUBLE_QUOTED); fail_unless(check > 0, @@ -2113,7 +2118,17 @@ START_TEST(test_format) "sdb_data_format(type=%s) used wrong format: %s; expected: %s", SDB_TYPE_TO_STRING(datum->type), buf, golden_data[i].expected); - fail_unless((size_t)check <= sizeof(buf) - 2, + fail_unless(check_null == check, + "sdb_data_format(type=%s, NULL) = %d; " + "expected %d (matching sdb_data_format(type=%s, ))", + SDB_TYPE_TO_STRING(datum->type), check_null, + check, SDB_TYPE_TO_STRING(datum->type)); + fail_unless(check == strlen(golden_data[i].expected), + "sdb_data_format(type=%s) = %d; expected %zu (strlen)", + SDB_TYPE_TO_STRING(datum->type), check, + strlen(golden_data[i].expected)); + + fail_unless(check <= sizeof(buf) - 2, "sdb_data_format(type=%s) wrote %d bytes; " "expected <= %zu based on sdb_data_strlen()", SDB_TYPE_TO_STRING(datum->type), check, sizeof(buf) - 2); diff --git a/t/unit/utils/proto_test.c b/t/unit/utils/proto_test.c index 01b6350..e7e8d44 100644 --- a/t/unit/utils/proto_test.c +++ b/t/unit/utils/proto_test.c @@ -163,7 +163,7 @@ START_TEST(test_marshal_data) sdb_data_t datum = SDB_DATA_INIT; ssize_t check; - if (sdb_data_format(&golden_data[i].datum, v1, sizeof(v1), 0) < 0) + if (! sdb_data_format(&golden_data[i].datum, v1, sizeof(v1), 0)) snprintf(v1, sizeof(v1), ""); fail_unless(len == golden_data[i].expected_len, @@ -189,7 +189,7 @@ START_TEST(test_marshal_data) } check = sdb_proto_unmarshal_data(buf, len, &datum); - if (sdb_data_format(&datum, v2, sizeof(v2), 0) < 0) + if (! sdb_data_format(&datum, v2, sizeof(v2), 0)) snprintf(v2, sizeof(v2), ""); if (sdb_data_isnull(&golden_data[i].datum)) @@ -499,7 +499,7 @@ START_TEST(test_marshal_attribute) pos, (int)buf[pos], (int)golden_data[i].expected[pos]); } - if (sdb_data_format(&golden_data[i].attr.value, v1, sizeof(v1), 0) < 0) + if (! sdb_data_format(&golden_data[i].attr.value, v1, sizeof(v1), 0)) snprintf(v1, sizeof(v1), ""); check = sdb_proto_unmarshal_attribute(buf, len, &attr); @@ -507,7 +507,7 @@ START_TEST(test_marshal_attribute) "<%zu> sdb_proto_unmarshal_attribute(buf<%s>) = %zi; expected: %zi", i, golden_data[i].attr.key, check, len); - if (sdb_data_format(&attr.value, v2, sizeof(v2), 0) < 0) + if (! sdb_data_format(&attr.value, v2, sizeof(v2), 0)) snprintf(v2, sizeof(v2), ""); fail_unless((attr.last_update == golden_data[i].attr.last_update) && (attr.parent_type == golden_data[i].attr.parent_type) -- 2.30.2