On Fri, Mar 25, 2011 at 3:32 PM, Alexander Best <arun...@freebsd.org> wrote:
> On Fri Mar 25 11, Xin LI wrote:
>> FYI I have a patch and I have incorporated some of Alexander's idea.
>>
>> Difference:
>>
>>  - Use of both HN_DIVISOR_1000 and HN_IEC_PREFIXES triggers an
>> assertion.  I think it doesn't make sense to return since this is an
>> API violation and we should just tell the caller explicitly;
>
> actually i vote for removing all asserts in humanize_number.c and return -1
> based upon the later checks.
>
> the existing
>
> assert(buf != NULL);
> assert(suffix != NULL);
>
> checks aren't really needed, since buf and suffix are also checked later on. 
> so
> just having:

Well, one of my believes is that a program should crash as early as
possible, and with clear statement about "Why I crashed", when it's
compiled with debugging aids, like assertions.  To test or not to test
these cases in a release binary on the other hand really depends on
whether there is security or other bad implications.  This generally
makes developers' life easier, as they don't have to pursue into the
code to find out why the program crashed, etc.

Unlike system calls, humanize_number(3) does not indicate what's wrong
via errno, e.g. it tells you "No I can't" rather than a reason of "Why
I can't do that".  Assertions here gives it an opportunity to say it
loudly.

If however the program is compiled with -DNDEBUG, these assertions
would became no-op.  At this stage, in my opinion, only basic tests
should be done and we fall back to returning -1, or at least, not
crash the program in a mysterious way.

For this reasons, I think the assertion here against flags is right,
it does not hurt if we proceed with both flags set, as we do not
access undefined memory nor overwrite undefined memory.  Furthermore,
these values are more likely to be hard-wired at caller, where the
assertion should catch the case.

>        if (scale <= 0 || (scale >= maxscale &&
>            (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
>                return (-1);

I think this one is good to have for both assertion and tests.  Note
that I think it should be scale < 0 here, scale == 0 seems to be a
valid value.

>        if (buf == NULL || suffix == NULL)
>                return (-1);

This duplication is necessary in my opinion.  It's a protection
against NULL pointer deference at runtime.

>        if ((flags & (HN_DIVISOR_1000 | HN_IEC_PREFIXES)) == 0)
>                return (-1);

I'd vote no for this one for the reason above.

>>  - DIVISOR_1000 and !1000 cases use just same prefixes, so merge them
>> while keeping divisor intact;
>
> good idea. however i think you should add a comment to point out that the
> default behavior is !DIVISOR_1000 && !HN_IEC_PREFIXES. one has to look very
> closely to find out.

Will do.

> #define HN_DECIMAL              0x01
> #define HN_NOSPACE              0x02
> #define HN_B                    0x04
> #define HN_DIVISOR_1000         0x08
> #define HN_IEC_PREFIXES         0x40
>
> #define HN_GETSCALE             0x10
> #define HN_AUTOSCALE            0x20

Thinking again and I think we are just fine to use HN_IEC_PREFIXES ==
0x10 here.  I don't think there is a reason why we can't use 0x10 for
flags.

Here is what in my mind.  I have stolen some comments from your
version of patch to explain the meaning of the HN_IEC_PREFIXES option
as well.

-- 
Xin LI <delp...@delphij.net> http://www.delphij.net
Index: humanize_number.c
===================================================================
--- humanize_number.c	(revision 220009)
+++ humanize_number.c	(working copy)
@@ -42,45 +42,59 @@
 #include <locale.h>
 #include <libutil.h>
 
+static const int maxscale = 7;
+
 int
 humanize_number(char *buf, size_t len, int64_t quotient,
     const char *suffix, int scale, int flags)
 {
 	const char *prefixes, *sep;
-	int	i, r, remainder, maxscale, s1, s2, sign;
+	int	i, r, remainder, s1, s2, sign;
 	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)));
 
 	remainder = 0;
 
-	if (flags & HN_DIVISOR_1000) {
-		/* SI for decimal multiplies */
-		divisor = 1000;
-		if (flags & HN_B)
-			prefixes = "B\0k\0M\0G\0T\0P\0E";
-		else
-			prefixes = "\0\0k\0M\0G\0T\0P\0E";
-	} else {
+	if (flags & HN_IEC_PREFIXES) {
+		baselen = 2;
 		/*
-		 * binary multiplies
-		 * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+		 * Use the prefixes for power of two recommended by
+		 * the International Electrotechnical Commission
+		 * (IEC) in IEC 80000-3 (superseeding IEC 60027-2)
+		 * (i.e. Ki, Mi, Gi...).
+		 *
+		 * HN_IEC_PREFIXES implies a divisor of 1024 here
+		 * (use of HN_DIVISOR_1000 would have triggered
+		 * an assertion earlier).
 		 */
 		divisor = 1024;
 		if (flags & HN_B)
-			prefixes = "B\0K\0M\0G\0T\0P\0E";
+			prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
 		else
-			prefixes = "\0\0K\0M\0G\0T\0P\0E";
+			prefixes = "\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei";
+	} else {
+		baselen = 1;
+		if (flags & HN_DIVISOR_1000)
+			divisor = 1000;
+		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";
 	}
 
-#define	SCALE2PREFIX(scale)	(&prefixes[(scale) << 1])
-	maxscale = 7;
+#define	SCALE2PREFIX(scale)	(&prefixes[(scale) * 3])
 
-	if (scale >= maxscale &&
-	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+	if (scale < 0 || (scale >= maxscale &&
+	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0))
 		return (-1);
 
 	if (buf == NULL || suffix == NULL)
@@ -91,10 +105,10 @@
 	if (quotient < 0) {
 		sign = -1;
 		quotient = -quotient;
-		baselen = 3;		/* sign, digit, prefix */
+		baselen += 2;		/* sign, digit */
 	} else {
 		sign = 1;
-		baselen = 2;		/* digit, prefix */
+		baselen += 1;		/* digit */
 	}
 	if (flags & HN_NOSPACE)
 		sep = "";
Index: libutil.h
===================================================================
--- libutil.h	(revision 220009)
+++ libutil.h	(working copy)
@@ -220,7 +220,9 @@
 #define HN_NOSPACE		0x02
 #define HN_B			0x04
 #define HN_DIVISOR_1000		0x08
+#define HN_IEC_PREFIXES		0x10
 
+/* maxscale = 0x07 */
 #define HN_GETSCALE		0x10
 #define HN_AUTOSCALE		0x20
 
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"

Reply via email to