Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Oct 2013 22:22:57 +0000 (UTC)
From:      John-Mark Gurney <jmg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r256130 - in head: lib/libutil tools/regression/lib/libutil
Message-ID:  <201310072222.r97MMvAN009304@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jmg
Date: Mon Oct  7 22:22:57 2013
New Revision: 256130
URL: http://svnweb.freebsd.org/changeset/base/256130

Log:
  don't assert on bad args, instead return an error..
  
  Since so many programs don't check return value, always NUL terminate
  the buf...
  
  fix rounding when using base 1024 (the bug that started it all)...
  
  add a set of test cases so we can make sure that things don't break
  in the future...
  
  Thanks to Clifton Royston for testing and the test program...
  
  Approved by:	re (hrs, glebius)
  MFC after:	1 week

Added:
  head/tools/regression/lib/libutil/test-humanize_number.c   (contents, props changed)
  head/tools/regression/lib/libutil/test-humanize_number.t   (contents, props changed)
Modified:
  head/lib/libutil/humanize_number.3
  head/lib/libutil/humanize_number.c
  head/tools/regression/lib/libutil/Makefile

Modified: head/lib/libutil/humanize_number.3
==============================================================================
--- head/lib/libutil/humanize_number.3	Mon Oct  7 22:03:40 2013	(r256129)
+++ head/lib/libutil/humanize_number.3	Mon Oct  7 22:22:57 2013	(r256130)
@@ -28,7 +28,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd Apr 12, 2011
+.Dd October 7, 2013
 .Dt HUMANIZE_NUMBER 3
 .Os
 .Sh NAME
@@ -140,7 +140,7 @@ The following flags may be passed in
 .Fa flags :
 .Bl -tag -width ".Dv HN_DIVISOR_1000" -offset indent
 .It Dv HN_DECIMAL
-If the final result is less than 10, display it using one digit.
+If the final result is less than 10, display it using one decimal place.
 .It Dv HN_NOSPACE
 Do not put a space between
 .Fa number
@@ -160,13 +160,18 @@ This flag has no effect when
 is also specified.
 .El
 .Sh RETURN VALUES
-The
-.Fn humanize_number
-function returns the number of characters stored in
+Upon success, the
+.Nm
+function returns the number of characters that would have been stored in
 .Fa buf
 (excluding the terminating
 .Dv NUL )
-upon success, or \-1 upon failure.
+if
+.Fa buf
+was large enough, or \-1 upon failure.
+Even upon failure, the contents of
+.Fa buf
+may be modified.
 If
 .Dv HN_GETSCALE
 is specified, the prefix index number will be returned instead.

Modified: head/lib/libutil/humanize_number.c
==============================================================================
--- head/lib/libutil/humanize_number.c	Mon Oct  7 22:03:40 2013	(r256129)
+++ head/lib/libutil/humanize_number.c	Mon Oct  7 22:22:57 2013	(r256130)
@@ -2,6 +2,7 @@
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * Copyright 2013 John-Mark Gurney <jmg@FreeBSD.org>
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -50,15 +51,26 @@ humanize_number(char *buf, size_t len, i
 {
 	const char *prefixes, *sep;
 	int	i, r, remainder, s1, s2, sign;
+	int	divisordeccut;
 	int64_t	divisor, max;
 	size_t	baselen;
 
-	assert(buf != NULL);
-	assert(suffix != NULL);
-	assert(scale >= 0);
-	assert(scale < maxscale || (((scale & (HN_AUTOSCALE | HN_GETSCALE)) != 0)));
-	assert(!((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES)));
+	/* Since so many callers don't check -1, NUL terminate the buffer */
+	if (len > 0)
+		buf[0] = '\0';
 
+	/* validate args */
+	if (buf == NULL || suffix == NULL)
+		return (-1);
+	if (scale < 0)
+		return (-1);
+	else if (scale >= maxscale &&
+	    ((scale & ~(HN_AUTOSCALE|HN_GETSCALE)) != 0))
+		return (-1);
+	if ((flags & HN_DIVISOR_1000) && (flags & HN_IEC_PREFIXES))
+		return (-1);
+
+	/* setup parameters */
 	remainder = 0;
 
 	if (flags & HN_IEC_PREFIXES) {
@@ -73,34 +85,32 @@ humanize_number(char *buf, size_t len, i
 		 * an assertion earlier).
 		 */
 		divisor = 1024;
+		divisordeccut = 973;	/* ceil(.95 * 1024) */
 		if (flags & HN_B)
 			prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
 		else
 			prefixes = "\0\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
 	} else {
 		baselen = 1;
-		if (flags & HN_DIVISOR_1000)
+		if (flags & HN_DIVISOR_1000) {
 			divisor = 1000;
-		else
+			divisordeccut = 950;
+			if (flags & HN_B)
+				prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
+			else
+				prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
+		} else {
 			divisor = 1024;
-
-		if (flags & HN_B)
-			prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
-		else
-			prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E";
+			divisordeccut = 973;	/* ceil(.95 * 1024) */
+			if (flags & HN_B)
+				prefixes = "B\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E";
+			else
+				prefixes = "\0\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E";
+		}
 	}
 
 #define	SCALE2PREFIX(scale)	(&prefixes[(scale) * 3])
 
-	if (scale < 0 || (scale >= maxscale &&
-	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
-		return (-1);
-
-	if (buf == NULL || suffix == NULL)
-		return (-1);
-
-	if (len > 0)
-		buf[0] = '\0';
 	if (quotient < 0) {
 		sign = -1;
 		quotient = -quotient;
@@ -132,8 +142,8 @@ humanize_number(char *buf, size_t len, i
 		 * divide once more.
 		 */
 		for (i = 0;
-		    (quotient >= max || (quotient == max - 1 && remainder >= 950)) &&
-		    i < maxscale; i++) {
+		    (quotient >= max || (quotient == max - 1 &&
+		    remainder >= divisordeccut)) && i < maxscale; i++) {
 			remainder = quotient % divisor;
 			quotient /= divisor;
 		}
@@ -148,20 +158,22 @@ humanize_number(char *buf, size_t len, i
 	}
 
 	/* If a value <= 9.9 after rounding and ... */
-	if (quotient <= 9 && remainder < 950 && i > 0 && flags & HN_DECIMAL) {
-		/* baselen + \0 + .N */
-		if (len < baselen + 1 + 2)
-			return (-1);
-		s1 = (int)quotient + ((remainder + 50) / 1000);
-		s2 = ((remainder + 50) / 100) % 10;
+	/*
+	 * XXX - should we make sure there is enough space for the decimal
+	 * place and if not, don't do HN_DECIMAL?
+	 */
+	if (((quotient == 9 && remainder < divisordeccut) || quotient < 9) &&
+	    i > 0 && flags & HN_DECIMAL) {
+		s1 = (int)quotient + ((remainder * 10 + divisor / 2) /
+		    divisor / 10);
+		s2 = ((remainder * 10 + divisor / 2) / divisor) % 10;
 		r = snprintf(buf, len, "%d%s%d%s%s%s",
 		    sign * s1, localeconv()->decimal_point, s2,
 		    sep, SCALE2PREFIX(i), suffix);
 	} else
 		r = snprintf(buf, len, "%" PRId64 "%s%s%s",
-		    sign * (quotient + (remainder + 50) / 1000),
+		    sign * (quotient + (remainder + divisor / 2) / divisor),
 		    sep, SCALE2PREFIX(i), suffix);
 
 	return (r);
 }
-

Modified: head/tools/regression/lib/libutil/Makefile
==============================================================================
--- head/tools/regression/lib/libutil/Makefile	Mon Oct  7 22:03:40 2013	(r256129)
+++ head/tools/regression/lib/libutil/Makefile	Mon Oct  7 22:22:57 2013	(r256130)
@@ -1,6 +1,7 @@
 # $FreeBSD$
 
-TESTS=	test-trimdomain test-trimdomain-nodomain test-flopen test-grp test-pidfile
+TESTS=	test-trimdomain test-trimdomain-nodomain test-flopen test-grp \
+	test-pidfile test-humanize_number
 CFLAGS+= -g -Wall -Wextra -Werror -lutil
 
 .PHONY: tests

Added: head/tools/regression/lib/libutil/test-humanize_number.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/lib/libutil/test-humanize_number.c	Mon Oct  7 22:22:57 2013	(r256130)
@@ -0,0 +1,592 @@
+/*-
+ * Copyright 2012 Clifton Royston
+ * Copyright 2013 John-Mark Gurney
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <math.h>
+#include <unistd.h>
+#include <limits.h>
+
+extern char * optarg;
+
+#define	MAX_STR_FLAGS_RESULT	80
+#define MAX_INT_STR_DIGITS	12
+
+static const int64_t halfExabyte = (int64_t)500*1000*1000*1000*1000*1000L;
+
+static struct {
+	int retval;
+	const char *res;
+	int64_t num;
+	int flags;
+	int scale;
+} test_args[] = {
+	/* tests 0-13 test 1000 suffixes */
+	{ 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+
+	/* tests 14-27 test 1024 suffixes */
+	{ 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE },
+	{ 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE },
+	{ 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE },
+	{ 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE },
+	{ 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE },
+	{ 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+
+	/* tests 28-37 test rounding */
+	{ 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE },
+	{ 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE },
+	{ 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE },
+	{ 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE },
+	{ 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE },
+
+	/* tests 38-61 test specific scale factors with 1000 divisor */
+	{ 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1 },
+	{ 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1 },
+	{ 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2 },
+	{ 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2 },
+	{ 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3 },
+	{ 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3 },
+	{ 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4 },
+	{ 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4 },
+	{ 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+	{ 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+	{ 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1 },
+	{ 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1 },
+	{ 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2 },
+	{ 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2 },
+	{ 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3 },
+	{ 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3 },
+	{ 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4 },
+	{ 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4 },
+	{ 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+	{ 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+	{ 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+
+	/* tests 62-85 test specific scale factors with 1024 divisor */
+	{ 3, "0 K", (int64_t)0L, 0, 1 },
+	{ 3, "1 K", (int64_t)512L, 0, 1 },
+	{ 3, "0 M", (int64_t)512L, 0, 2 },
+	{ 3, "1 M", (int64_t)512*1024L, 0, 2 },
+	{ 3, "0 G", (int64_t)512*1024L, 0, 3 },
+	{ 3, "1 G", (int64_t)512*1024*1024L, 0, 3 },
+	{ 3, "0 T", (int64_t)512*1024*1024L, 0, 4 },
+	{ 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4 },
+	{ 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5 },
+	{ 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5 },
+	{ 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 K", (int64_t)1L, 0, 1 },
+	{ 3, "2 K", (int64_t)1536L, 0, 1 },
+	{ 3, "0 M", (int64_t)1536L, 0, 2 },
+	{ 3, "2 M", (int64_t)1536*1024L, 0, 2 },
+	{ 3, "0 G", (int64_t)1536*1024L, 0, 3 },
+	{ 3, "2 G", (int64_t)1536*1024*1024L, 0, 3 },
+	{ 3, "0 T", (int64_t)1536*1024*1024L, 0, 4 },
+	{ 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4 },
+	{ 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5 },
+	{ 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5 },
+	{ 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6 },
+
+	/* tests 86-99 test invalid specific scale values of < 0 or >= 7 with
+	and without HN_DIVISOR_1000 set */
+	/*  all should return errors with new code; with old, the latter 3
+	are instead processed as if having AUTOSCALE and/or GETSCALE set */
+	{ -1, "", (int64_t)1L, 0, 7 },
+	{ -1, "", (int64_t)1L, HN_DIVISOR_1000, 7 },
+	{ -1, "", (int64_t)1L, 0, 1000 },
+	{ -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000 },
+	{ -1, "", (int64_t)0L, 0, 1000*1000 },
+	{ -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000 },
+	{ -1, "", (int64_t)0L, 0, INT_MAX },
+	{ -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX },
+
+	/* Negative scale values are not handled well
+	 by the existing library routine - should report as error */
+	/*  all should return errors with new code, fail assertion with old */
+
+	{ -1, "", (int64_t)1L, 0, -1 },
+	{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -1 },
+	{ -1, "", (int64_t)1L, 0, -1000 },
+	{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000 },
+
+	/* __INT_MIN doesn't print properly, skipped. */
+
+	{ -1, "", (int64_t)1L, 0, -__INT_MAX },
+	{ -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX },
+
+
+	/* tests for scale == 0, without autoscale */
+	/* tests 100-114 test scale 0 with 1000 divisor - print first N digits */
+	{ 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0 },
+	{ 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0 },
+	{ 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0 },
+	{ 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE },
+	{ 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE },
+	{ 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE },
+	{ 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0 },
+	{ 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0 },
+	{ 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0 },
+	{ 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0 },
+	{ 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0 },
+	{ 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0 },
+	{ 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0 },
+	{ 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0 },
+	{ 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0 },
+
+	/* tests 115-126 test scale 0 with 1024 divisor - print first N digits */
+	{ 2, "0 ", (int64_t)0L, 0, 0 },
+	{ 2, "1 ", (int64_t)1L, 0, 0 },
+	{ 3, "10 ", (int64_t)10L, 0, 0 },
+	{ 4, "150", (int64_t)150L, 0, 0 },
+	{ 4, "500", (int64_t)500L, 0, 0 },
+	{ 4, "999", (int64_t)999L, 0, 0 },
+	{ 5, "100", (int64_t)1000L, 0, 0 },
+	{ 5, "150", (int64_t)1500L, 0, 0 },
+	{ 7, "500", (int64_t)500*1000L, 0, 0 },
+	{ 8, "150", (int64_t)1500*1000L, 0, 0 },
+	{ 10, "500", (int64_t)500*1000*1000L, 0, 0 },
+	{ 11, "150", (int64_t)1500*1000*1000L, 0, 0 },
+
+	/* Test boundary cases for very large positive/negative number formatting */
+	/* Explicit scale, divisor 1024 */
+
+	/* XXX = requires length 5 (buflen 6) for some cases*/
+	/* KLUDGE - test loop below will bump length 5 up to 5 */
+	{ 3, "8 E",   INT64_MAX, 0, 6 },
+	{ 4, "-8 E", -INT64_MAX, 0, 6 },
+	{ 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6 },
+	{ 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5 },
+	{ 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5 },
+	{ 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5 },
+	{ 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5 },
+	{ 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5 },
+	{ 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5 },
+
+	/* Explicit scale, divisor 1000 */
+	{ 3, "9 E",   INT64_MAX, HN_DIVISOR_1000, 6 },
+	{ 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000,  6 },
+	{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  6 },
+	{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  6 },
+	{ 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  6 },
+	{ 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  6 },
+	{ 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  5 },
+	{ 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  5 },
+	{ 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  5 },
+	{ 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  5 },
+
+	/* Autoscale, divisor 1024 */
+	{ 3, "8 E",   INT64_MAX, 0, HN_AUTOSCALE },
+	{ 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE },
+	{ 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	{ 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+	/* Autoscale, divisor 1000 */
+	{ 3, "9 E",   INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+
+	/* 0 scale, divisor 1024 */
+	{ 12, "skdj",  INT64_MAX, 0, 0 },
+	{ 21, "-9223", -INT64_MAX, 0, 0 },
+	{ 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0 },
+	{ 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0 },
+	{ 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0 },
+	{ 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0 },
+	{ 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0 },
+	{ 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0 },
+
+	/* 0 scale, divisor 1000 */
+	/* XXX - why does this fail? */
+	{ -1, "", INT64_MAX, HN_DIVISOR_1000, 0 },
+	{ 21, "-9223", -INT64_MAX, HN_DIVISOR_1000,  0 },
+	{ 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+	{ 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+	{ 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+	{ 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+	/* Expected to pass */
+	{ 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+	{ 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000,  0 },
+
+
+
+	/* Need to implement tests for GETSCALE */
+/*	{ ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE },
+	...
+*/
+        /* Tests for HN_DECIMAL */
+        /* Positive, Autoscale */
+	{ 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+	{ 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	/* XXX - shouldn't the following two be "10. M"? */
+	{ 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+
+        /* Negative, Autoscale - should pass */
+	{ 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+	{ 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE },
+	{ 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE },
+
+	/* Positive/negative, at maximum scale */
+	{ 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+        /* Negatives work with latest rev only: */
+	{ 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+	{ 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+	{ 5, "8.0 E",   INT64_MAX, HN_DECIMAL, HN_AUTOSCALE },
+	{ 5, "7.9 E",   INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE },
+	{ 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE },
+	{ 6, "-7.9 ",   -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE },
+
+	/* Positive, Fixed scales */
+	{ 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+	{ 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+	{ 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+	{ 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+	{ 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 },
+	{ 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+	{ 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 },
+	/* Positive/negative, at maximum scale */
+	{ 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+	{ 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+	{ 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6 },
+
+	/* HN_DECIMAL + binary + fixed scale cases not completed */
+	{ 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1 },
+	{ 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2 },
+
+	/* Negative, Fixed scales */
+        /* Not yet added, but should work with latest rev */
+
+};
+
+
+/* Command line options usage */
+static void
+usage(char * progname) {
+	printf("%s: tests libutil humanize_number function\n", progname);
+	printf("Usage: %s [-nE] [-l num] [-v]\n\n", progname);
+	printf("Options:\n");
+	printf("\t-l num\tSet max length for result; buflen = num + 1\n");
+	printf("\t\t  (NOTE: does not change expected result strings.)\n");
+	printf("\t-n\tInclude negative scale tests, which cause older libutil\n");
+	printf("\t\t  version of function to coredump with assertion failure\n");
+	printf("\t-E\tInclude numbers > 1/2 Exa[byte] which currently fail\n");
+	printf("\t-v\tVerbose - always print summary results\n");
+	printf("\t-h, -?\tShow options\n");
+}
+
+/* Parse command line options */
+static void
+read_options(int argc, char * const argv[], size_t *bufLength,
+    int *includeNegativeScale, int *includeExabytes, int *verbose) {
+	int ch;
+	size_t temp;
+
+	while ((ch = getopt(argc, argv, "nEh?vl:")) != -1) {
+		switch (ch) {
+			default:
+				usage(argv[0]);
+				exit(1);
+				break;	/* UNREACHABLE */
+			case 'h' :
+			case '?' :
+				usage(argv[0]);
+				exit(0);
+				break;	/* UNREACHABLE */
+			case 'l' :
+				sscanf(optarg, "%zu", &temp);
+				*bufLength = temp + 1;
+				break;
+			case 'n' :
+				*includeNegativeScale = 1;
+				break;
+			case 'E' :
+				*includeExabytes = 1;
+				break;
+			case 'v' :
+				*verbose = 1;
+				break;
+		}
+	}
+}
+
+static struct {
+	int value;
+	const char *name;
+ } flags[] = {
+	{ HN_AUTOSCALE, "HN_AUTOSCALE" },
+	{ HN_GETSCALE, "HN_GETSCALE" },
+	{ HN_DIVISOR_1000, "HN_DIVISOR_1000"},
+	{ HN_B, "HN_B"},
+	{ HN_DECIMAL, "HN_DECIMAL"},
+};
+
+static const char *separator = "|";
+
+/* Format flags parameter for meaningful display */
+static char *
+str_flags(int hn_flags, char *noFlags) {
+	size_t i;
+	char * result;
+
+	result = malloc(MAX_STR_FLAGS_RESULT);
+	result[0] = '\0';
+
+	for (i = 0; i < sizeof flags / sizeof *flags; i++) {
+		if (hn_flags & flags[i].value) {
+			if (*result != 0)
+				strlcat(result, separator,
+				    MAX_STR_FLAGS_RESULT);
+			strlcat(result, flags[i].name, MAX_STR_FLAGS_RESULT);
+		}
+	}
+
+	if (strlen(result) == 0)
+		strlcat(result, noFlags, MAX_STR_FLAGS_RESULT);
+	return result;
+}
+
+
+/* Format scale parameter for meaningful display */
+static char *
+str_scale(int scale) {
+	char *result;
+
+	if (scale == HN_AUTOSCALE || scale == HN_GETSCALE)
+		return str_flags(scale, "");
+
+	result = malloc(MAX_INT_STR_DIGITS);
+	result[0] = '\0';
+	snprintf(result, MAX_INT_STR_DIGITS, "%d", scale);
+	return result;
+}
+
+static void
+testskipped(size_t i)
+{
+
+	printf("ok %lu # skip - not turned on\n", i);
+}
+
+int
+main(int argc, char * const argv[])
+{
+	char *buf;
+	char *flag_str, *scale_str;
+	size_t i;
+	size_t errcnt, tested, skipped;
+	int r;
+	size_t buflen;
+	int includeNegScale;
+	int includeExabyteTests;
+	int verbose;
+
+	buflen = 4;
+	includeNegScale = 0;
+	includeExabyteTests = 0;
+	verbose = 0;
+
+	read_options(argc, argv, &buflen, &includeNegScale,
+	    &includeExabyteTests, &verbose);
+
+	buf = malloc(buflen);
+	errcnt = 0;
+	tested = 0;
+	skipped = 0;
+
+	if (buflen != 4)
+		printf("Warning: buffer size %zu != 4, expect some results to differ.\n", buflen);
+
+	printf("1..%lu\n", sizeof test_args / sizeof *test_args);
+	for (i = 0; i < sizeof test_args / sizeof *test_args; i++) {
+		/* KLUDGE */
+		if (test_args[i].num == INT64_MAX && buflen == 4) {
+		        /* Start final tests which require buffer of 6 */
+		        free(buf);
+		        buflen = 6;
+                        buf = malloc(buflen);
+                        if (verbose)
+                                printf("Buffer length increased to %zu\n",
+				    buflen);
+		}
+
+		if (test_args[i].scale < 0 && ! includeNegScale) {
+			skipped++;
+			testskipped(i);
+			continue;
+		}
+		if (test_args[i].num >= halfExabyte && ! includeExabyteTests) {
+			skipped++;
+			testskipped(i);
+			continue;
+		}
+
+		r = humanize_number(buf, buflen, test_args[i].num, "",
+		    test_args[i].scale, test_args[i].flags);
+		flag_str = str_flags(test_args[i].flags, "[no flags]");
+		scale_str = str_scale(test_args[i].scale);
+
+		if (r != test_args[i].retval) {
+			if (verbose)
+				printf("wrong return value on index %lu, buflen: %zu, got: %d + \"%s\", expected %d + \"%s\"; num = %" PRId64 ", scale = %s, flags= %s.\n",
+				    i, buflen, r, buf, test_args[i].retval,
+				    test_args[i].res, test_args[i].num,
+				    scale_str, flag_str);
+			else
+				printf("not ok %lu # return %d != %d\n", i, r,
+				    test_args[i].retval);
+			errcnt++;
+		} else if (strcmp(buf, test_args[i].res) != 0) {
+			if (verbose)
+				printf("result mismatch on index %lu, got: \"%s\", expected \"%s\"; num = %" PRId64 ", scale = %s, flags= %s.\n",
+				    i, buf, test_args[i].res, test_args[i].num,
+				    scale_str, flag_str);
+			else
+				printf("not ok %lu # buf \"%s\" != \"%s\"\n", i,
+				    buf, test_args[i].res);
+			errcnt++;
+		} else {
+			if (verbose)
+				printf("successful result on index %lu, returned %d, got: \"%s\"; num = %" PRId64 ", scale = %s, flags= %s.\n",
+				    i, r, buf, test_args[i].num, scale_str,
+				    flag_str);
+			else
+				printf("ok %lu\n", i);
+		}
+		tested++;
+	}
+
+	if (verbose)
+		printf("total errors: %lu/%lu tests, %lu skipped\n", errcnt,
+		    tested, skipped);
+
+	if (errcnt)
+		return 1;
+
+	return 0;
+}

Added: head/tools/regression/lib/libutil/test-humanize_number.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/lib/libutil/test-humanize_number.t	Mon Oct  7 22:22:57 2013	(r256130)
@@ -0,0 +1,10 @@
+#!/bin/sh
+# $FreeBSD$
+
+cd `dirname $0`
+
+executable=`basename $0 .t`
+
+make $executable 2>&1 > /dev/null
+
+exec ./$executable && echo humanize_numbers ok



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310072222.r97MMvAN009304>