str: add STR_MAX_CHARS().
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 24 Sep 2012 01:25:13 +0000 (10:55 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 24 Sep 2012 01:25:13 +0000 (10:55 +0930)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/str/str.h
ccan/str/test/compile_fail-STR_MAX_CHARS.c [new file with mode: 0644]
ccan/str/test/run-STR_MAX_CHARS.c [new file with mode: 0644]

index 14cd65ab38a3d418097ce49c26f625a79c4130f8..d4ced0d8914386b04034a439a3309c8cd9f46da7 100644 (file)
@@ -4,6 +4,7 @@
 #include "config.h"
 #include <string.h>
 #include <stdbool.h>
+#include <limits.h>
 #include <ctype.h>
 
 /**
@@ -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 (file)
index 0000000..74448c1
--- /dev/null
@@ -0,0 +1,23 @@
+#include <ccan/str/str.h>
+
+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 (file)
index 0000000..ae6969c
--- /dev/null
@@ -0,0 +1,59 @@
+#include <ccan/str/str.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ccan/tap/tap.h>
+#include <stdint.h>
+
+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();
+}