From 049ae7d0ade969c44d0ffab043f507fa7827bf09 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 24 Sep 2012 10:55:13 +0930 Subject: [PATCH] str: add STR_MAX_CHARS(). Signed-off-by: Rusty Russell --- ccan/str/str.h | 28 ++++++++++ ccan/str/test/compile_fail-STR_MAX_CHARS.c | 23 +++++++++ ccan/str/test/run-STR_MAX_CHARS.c | 59 ++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 ccan/str/test/compile_fail-STR_MAX_CHARS.c create mode 100644 ccan/str/test/run-STR_MAX_CHARS.c diff --git a/ccan/str/str.h b/ccan/str/str.h index 14cd65ab..d4ced0d8 100644 --- a/ccan/str/str.h +++ b/ccan/str/str.h @@ -4,6 +4,7 @@ #include "config.h" #include #include +#include #include /** @@ -72,6 +73,33 @@ static inline bool strends(const char *str, const char *postfix) */ size_t strcount(const char *haystack, const char *needle); +/** + * STR_MAX_CHARS - Maximum possible size of numeric string for this type. + * @type_or_expr: a pointer or integer type or expression. + * + * This provides enough space for a nul-terminated string which represents the + * largest possible value for the type or expression. + * + * Note: The implementation adds extra space so hex values or negative + * values will fit (eg. sprintf(... "%p"). ) + * + * Example: + * char str[STR_MAX_CHARS(i)]; + * + * sprintf(str, "%i", i); + */ +#define STR_MAX_CHARS(type_or_expr) \ + ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \ + + STR_MAX_CHARS_TCHECK_(type_or_expr)) + +#if HAVE_TYPEOF +/* Only a simple type can have 0 assigned, so test that. */ +#define STR_MAX_CHARS_TCHECK_(type_or_expr) \ + ({ typeof(type_or_expr) x = 0; (void)x; 0; }) +#else +#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0 +#endif + /** * cisalnum - isalnum() which takes a char (and doesn't accept EOF) * @c: a character diff --git a/ccan/str/test/compile_fail-STR_MAX_CHARS.c b/ccan/str/test/compile_fail-STR_MAX_CHARS.c new file mode 100644 index 00000000..74448c1b --- /dev/null +++ b/ccan/str/test/compile_fail-STR_MAX_CHARS.c @@ -0,0 +1,23 @@ +#include + +struct s { + int val; +}; + +int main(int argc, char *argv[]) +{ + struct s +#ifdef FAIL +#if !HAVE_TYPEOF + #error We need typeof to check STR_MAX_CHARS. +#endif +#else + /* A pointer is OK. */ + * +#endif + val; + char str[STR_MAX_CHARS(val)]; + + str[0] = '\0'; + return str[0] ? 0 : 1; +} diff --git a/ccan/str/test/run-STR_MAX_CHARS.c b/ccan/str/test/run-STR_MAX_CHARS.c new file mode 100644 index 00000000..ae6969c7 --- /dev/null +++ b/ccan/str/test/run-STR_MAX_CHARS.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char str[1000]; + struct { + uint8_t u1byte; + int8_t s1byte; + uint16_t u2byte; + int16_t s2byte; + uint32_t u4byte; + int32_t s4byte; + uint64_t u8byte; + int64_t s8byte; + void *ptr; + } types; + + plan_tests(13); + + memset(&types, 0xFF, sizeof(types)); + + /* Hex versions */ + sprintf(str, "0x%llx", (unsigned long long)types.u1byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); + sprintf(str, "0x%llx", (unsigned long long)types.u2byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); + sprintf(str, "0x%llx", (unsigned long long)types.u4byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); + sprintf(str, "0x%llx", (unsigned long long)types.u8byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); + + /* Decimal versions */ + sprintf(str, "%u", types.u1byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); + sprintf(str, "%d", types.s1byte); + ok1(strlen(str) < STR_MAX_CHARS(types.s1byte)); + sprintf(str, "%u", types.u2byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); + sprintf(str, "%d", types.s2byte); + ok1(strlen(str) < STR_MAX_CHARS(types.s2byte)); + sprintf(str, "%u", types.u4byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); + sprintf(str, "%d", types.s4byte); + ok1(strlen(str) < STR_MAX_CHARS(types.s4byte)); + sprintf(str, "%llu", (unsigned long long)types.u8byte); + ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); + sprintf(str, "%lld", (long long)types.s8byte); + ok1(strlen(str) < STR_MAX_CHARS(types.s8byte)); + + /* Pointer version. */ + sprintf(str, "%p", types.ptr); + ok1(strlen(str) < STR_MAX_CHARS(types.ptr)); + + return exit_status(); +} -- 2.39.2