[PATCH 5/9 V2] vsprintf: add %w and %w support to print unit

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Thu Sep 2 15:41:46 EDT 2010


Show a '%w' or %W thing.  This will show a unit
at format xxx[.xxx][ ][ kMG] with iEEE 1541 support

The precision can not excess the base kMG of the current unit
otherwise it will be automatically reduce

If no precision is specified and there is rest we will use a default
precision of 3 as 66.667 M or 66.667M

%#w or %#W will add a space between the value and the unit

The base will be typically 1000 for Hz or B and 1024 for iB
for 1024 the i is automactically add for val >= 1024

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
 include/linux/kernel.h |   20 ++++++++++
 lib/vsprintf.c         |   91 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index e9e2f07..b605946 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -5,6 +5,26 @@
 #include <linux/barebox-wrapper.h>
 
 /*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define DIV_ROUND_CLOSEST(x, divisor)(			\
+{							\
+	typeof(divisor) __divisor = divisor;		\
+	(((x) + ((__divisor) / 2)) / (__divisor));	\
+}							\
+)
+
+/*
  * min()/max()/clamp() macros that also do
  * strict type-checking.. See the
  * "unnecessary" pointer comparison.
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 6066845..18ba371 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -254,6 +254,88 @@ static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int
 }
 
 /*
+ * Show a '%w' or %W thing.  This will show a unit
+ * at format xxx[.xxx][ ][ kMG] with iEEE 1541 support
+ *
+ * The precision can not excess the base kMG of the current unit
+ * otherwise it will be automatically reduce
+ *
+ * If no precision is specified and there is rest we will use a default
+ * precision of 3 as 66.667 M or 66.667M
+ *
+ * %#w or %#W will add a space between the value and the unit
+ *
+ * The base will be typically 1000 for Hz or B and 1024 for iB
+ * for 1024 the i is automactically add for val >= 1024
+ */
+static char *unit_string(char *buf, char *end, long val, int base, int field_width, int precision, int flags)
+{
+	long rest = 0;
+	long integer;
+	long pr = 3;
+	long pr_mul = 1;
+	long unit = 1;
+	char format[] = " kMG";
+	int pow, i;
+
+	for (pow = 0; pow < strlen(format) - 1; pow++) {
+		if (val < unit * base)
+			break;
+		unit *= base;
+	}
+
+	integer = val / unit;
+
+	if (precision != -1) {
+		if (precision > pow * 3)
+			precision = pow * 3;
+		pr = precision;
+	}
+
+	for (i = 0; i < pr; i++) {
+		pr_mul *= 10;
+	}
+
+	if (val % unit) {
+		rest = DIV_ROUND_CLOSEST(pr_mul * (val - (integer * unit)), unit);
+
+		if (rest >= pr_mul) {
+			rest -= pr_mul;
+			integer++;
+		}
+	}
+
+	buf = number(buf, end, integer, 10, field_width, -1, flags & ~LEFT);
+
+	if (rest != 0 || precision != -1) {
+		if (buf < end)
+			*buf = '.';
+		buf++;
+		buf = number(buf, end, rest, 10, -1, pr, flags | ZEROPAD);
+	}
+
+	/* use SPECIAL as SPACE could be used for the interger part */
+	if (flags & SPECIAL) {
+		if (buf < end)
+			*buf = ' ';
+		buf++;
+	}
+
+	if (pow > 0) {
+		if (buf < end)
+			*buf = format[pow];
+		buf++;
+		if (base == 1024) {
+			if (buf < end)
+				*buf = 'i';
+			buf++;
+		}
+	}
+
+	return buf;
+}
+
+/*
  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
  * by an extra set of alphanumeric characters that are extended format
  * specifiers.
@@ -291,6 +373,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
  * %pS output the name of a text symbol
  * %pF output the name of a function pointer
  * %pR output the address range in a struct resource
+ * %W and %w output at unit format with iEEE 1541 support
  *
  * The return value is the number of characters which would
  * be generated for the given input, excluding the trailing
@@ -421,6 +504,14 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 				str = string(str, end, va_arg(args, char *), field_width, precision, flags);
 				continue;
 
+			case 'W':
+				str = unit_string(str, end, va_arg(args, long), 1024, field_width, precision, flags);
+				continue;
+
+			case 'w':
+				str = unit_string(str, end, va_arg(args, long), 1000, field_width, precision, flags);
+				continue;
+
 			case 'p':
 				str = pointer(fmt+1, str, end,
 						va_arg(args, void *),
-- 
1.7.1




More information about the barebox mailing list