Subject: bin/15508: humanize_number(3)
To: None <gnats-bugs@gnats.netbsd.org>
From: Tomas Svensson <tsn@gbdev.net>
List: netbsd-bugs
Date: 02/06/2002 15:14:21
>Number:         15508
>Category:       bin
>Synopsis:       humanize_number(3)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Feb 06 07:16:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        NetBSD 1.5ZA
>Organization:
>Environment:
		NetBSD 1.5ZA
>Description:

Here is a new version of humanize_number(9) for libc to be used
in programs such as df(1)/du(1)/ls(1).

Differences from the kernel version are:

- the bytes argument is signed (negative sizes can be used).
- the divisor argument is replaced with a flag, see below.
- rounding is done like floating point numbers were used.
- the suffix-prefix K is changed to k, which should be correct
  according to standards.
- three flags can be used : HN_DECIMAL tells it to use one decimal
  for numbers less than 10, HN_NOSPACE removes the space between
  the number and the prefix, HN_DIVISOR_1000 makes the divisor
  1000 (otherwise 1024 is assumed) and HN_B will use the prefix "B" for
  numbers that would normally not have a prefix (bytes less than
  1000). Use 0 if no flags are used (not worth the trouble with
  varargs?).

>How-To-Repeat:
>Fix:
	
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

#define HN_DECIMAL	1
#define HN_NOSPACE      2	
#define HN_B		4
#define HN_DIVISOR_1000 8

int humanize_number(char *, size_t, int64_t, const char *, int);

int humanize_number(char *buf, size_t len, int64_t bytes,
        const char *suffix, int flags) {

	static const char prefixes[] = " kMGTPE";
	
	int	divisor, i, r;
	int64_t	max, s1, s2, sign;
	size_t	baselen, suffixlen;

	if (buf == NULL)
		return -1;

	if (len > 0)
		buf[0] = '\0';
	if (bytes < 0) {
		sign = -1;
		bytes *= -100;
		baselen = 4;
	} else {
		sign = 1;
		bytes *= 100;
		baselen = 3;
	}

	suffixlen = strlen(suffix);

	/* check if enough room for `x y' + suffix + `\0' */
	if (len < baselen + suffixlen + 1)
		return (-1);

	if (flags & HN_DIVISOR_1000)
		divisor = 1000;
	else
		divisor = 1024;

	max = 100;
	for (i = 0; i < len - suffixlen - baselen + ((flags & HN_NOSPACE) ?
             1 : 0) ; i++)
		max *= 10;

	for (i = 0; bytes >= max && i < sizeof(prefixes); i++)
		bytes /= divisor;

	if (bytes < 1000 && flags & HN_DECIMAL) {
		if (len < (baselen + 2  + ( (flags & HN_NOSPACE) || (i == 0 &&
		    !(flags & HN_B)) ? 0 : 1)))
			return (-1);
		s1 = bytes / 100;
		if ((s2 = (( (bytes % 100 ) + 5 ) /  10 ) ) == 10 ) {
			s1++;
			s2 = 0;
		}
		r = snprintf(buf, len, "%qd%s%qd%s%c%s", sign * s1, 
		    localeconv()->decimal_point, s2,
		    (i == 0 && !(flags & HN_B) ) || flags & HN_NOSPACE ?
		    "" : " ", (i == 0 && (flags & HN_B)) ? 'B' :
		    prefixes[i], suffix);
		
	} else
	r = snprintf(buf, len, "%qd%s%c%s", sign * ((bytes + 50) / 100), 
	    i == 0 || flags & HN_NOSPACE ? "" : " ", (i == 0 &&
	    (flags & HN_B)) ? 'B' : prefixes[i], suffix);

	return r;
}
>Release-Note:
>Audit-Trail:
>Unformatted: