Hello Jean-Christophe, On Thu, Sep 02, 2010 at 04:10:20PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote: > Show a '%w' or %W thing. > This will show a frequency or byte at format xxx[.xxx] [ kMG] > 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 > base will be typically 1000 for Hz or B and 1024 for iB I see this used e.g. as: printk("%WiB", somevalue) right? hmm, what if somevalue is say 5? If I understand correctly the output then is: "5 iB". > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> > --- > include/linux/kernel.h | 20 +++++++++++++ > lib/vsprintf.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 93 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..add8bd5 100644 > --- a/lib/vsprintf.c > +++ b/lib/vsprintf.c > @@ -254,6 +254,71 @@ static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int > } > > /* > + * Show a '%w' or %W thing. This will show a frequency or byte > + * at format xxx[.xxx] [ kMG] > + * 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 > + * base will be typically 1000 for Hz or B and 1024 for iB > + */ > +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, 0); > + > + if (rest != 0 || precision != -1) { > + if (buf < end) > + *buf = '.'; > + buf++; > + buf = number(buf, end, rest, 10, -1, pr, 0); > + } > + > + if (buf < end) > + *buf = ' '; > + buf++; > + if (buf < end && pow != 0) > + *buf = format[pow]; > + 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. I think the kernel documents all available formats in a single place. (Is that here in barebox? If yes, please add your new formats here, too.) > @@ -421,6 +486,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 > > > _______________________________________________ > barebox mailing list > barebox@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/barebox > -- Pengutronix e.K. | Uwe Kleine-König | Industrial Linux Solutions | http://www.pengutronix.de/ | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox