From 5923f6b13745827b763bde470de8aa1bb03cb7ff Mon Sep 17 00:00:00 2001
From: Kaspar Schleiser <kaspar@schleiser.de>
Date: Mon, 7 Dec 2015 16:35:19 +0100
Subject: [PATCH] sys: fmt: add fmt_u64_dec()

---
 sys/fmt/fmt.c     | 62 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/include/fmt.h | 24 ++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c
index ab2d594ad5..0c169e6211 100644
--- a/sys/fmt/fmt.c
+++ b/sys/fmt/fmt.c
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <unistd.h>
+#include <string.h>
 
 #ifdef __WITH_AVRLIBC__
 #include <stdio.h>  /* for fwrite() */
@@ -102,6 +103,60 @@ size_t fmt_u64_hex(char *out, uint64_t val)
     return fmt_bytes_hex_reverse(out, (uint8_t*) &val, 8);
 }
 
+size_t fmt_u64_dec(char *out, uint64_t val)
+{
+    uint32_t d[5];
+    uint32_t q;
+    size_t len = 0;
+
+    d[0] = val       & 0xFFFF;
+    d[1] = (val>>16) & 0xFFFF;
+    d[2] = (val>>32) & 0xFFFF;
+    d[3] = (val>>48) & 0xFFFF;
+
+    d[0] = 656 * d[3] + 7296 * d[2] + 5536 * d[1] + d[0];
+    q = d[0] / 10000;
+    d[0] = d[0] % 10000;
+
+    d[1] = q + 7671 * d[3] + 9496 * d[2] + 6 * d[1];
+    q = d[1] / 10000;
+    d[1] = d[1] % 10000;
+
+    d[2] = q + 4749 * d[3] + 42 * d[2];
+    q = d[2] / 10000;
+    d[2] = d[2] % 10000;
+
+    d[3] = q + 281 * d[3];
+    q = d[3] / 10000;
+    d[3] = d[3] % 10000;
+
+    d[4] = q;
+
+    int first = 4;
+
+    while (!d[first] && first) {
+        first--;
+    }
+
+    len = fmt_u32_dec(out, d[first]);
+    int total_len = len + (first * 4);
+
+    if (out) {
+        out += len;
+        memset(out, '0', total_len - len);
+        while(first) {
+            first--;
+            if (d[first]) {
+                size_t tmp = fmt_u32_dec(NULL, d[first]);
+                fmt_u32_dec(out+(4-tmp), d[first]);
+            }
+            out += 4;
+        }
+    }
+
+    return total_len;
+}
+
 size_t fmt_u32_dec(char *out, uint32_t val)
 {
     size_t len = 1;
@@ -248,6 +303,13 @@ void print_u64_hex(uint64_t val)
     print_u32_hex(val);
 }
 
+void print_u64_dec(uint64_t val)
+{
+    char buf[18];
+    size_t len = fmt_u64_dec(buf, val);
+    print(buf, len);
+}
+
 void print_str(const char* str)
 {
     print(str, fmt_strlen(str));
diff --git a/sys/include/fmt.h b/sys/include/fmt.h
index 02162504d9..09ce002482 100644
--- a/sys/include/fmt.h
+++ b/sys/include/fmt.h
@@ -101,6 +101,21 @@ size_t fmt_u64_hex(char *out, uint64_t val);
  */
 size_t fmt_u32_dec(char *out, uint32_t val);
 
+/**
+ * @brief Convert a uint64 value to decimal string.
+ *
+ * If @p out is NULL, will only return the number of bytes that would have
+ * been written.
+ *
+ * @note This adds ~400b of code when used.
+ *
+ * @param[out]  out  Pointer to output buffer, or NULL
+ * @param[in]   val  Value to convert
+ *
+ * @return      nr of digits written to (or needed in) @p out
+ */
+size_t fmt_u64_dec(char *out, uint64_t val);
+
 /**
  * @brief Convert a uint16 value to decimal string.
  *
@@ -244,6 +259,15 @@ void print_u32_hex(uint32_t val);
  */
 void print_u64_hex(uint64_t val);
 
+/**
+ * @brief Print uint64 value as decimal to stdout
+ *
+ * @note This used fmt_u64_dec(), which uses ~400b of code.
+ *
+ * @param[in]   val  Value to print
+ */
+void print_u64_dec(uint64_t val);
+
 /**
  * @brief Print null-terminated string to stdout
  *
-- 
GitLab