11/* $NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $ */
22
3- /*
3+ /*-
4+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5+ *
46 * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
7+ * Copyright 2013 John-Mark Gurney <jmg@FreeBSD.org>
58 * All rights reserved.
69 *
710 * This code is derived from software contributed to The NetBSD Foundation
3033 * POSSIBILITY OF SUCH DAMAGE.
3134 */
3235
36+ #include <sys/types.h>
3337#include <assert.h>
3438#include <inttypes.h>
3539#include <stdio.h>
3640#include <stdlib.h>
3741#include <string.h>
3842#include <locale.h>
3943
40- #include "xbps_api_impl.h"
4144#include "compat.h"
4245
46+
47+ static const int maxscale = 6 ;
48+
49+
4350int HIDDEN
44- humanize_number (char * buf , size_t len , int64_t bytes ,
45- const char * suffix , int scale , int flags )
51+ humanize_number (char * buf , size_t len , int64_t quotient ,
52+ const char * suffix , int scale , int flags )
4653{
4754 const char * prefixes , * sep ;
48- int b , i , r , maxscale , s1 , s2 , sign ;
55+ int i , r , remainder , s1 , s2 , sign ;
56+ int divisordeccut ;
4957 int64_t divisor , max ;
5058 size_t baselen ;
5159
52- assert ( buf != NULL );
53- assert ( suffix != NULL );
54- assert ( scale >= 0 ) ;
60+ /* Since so many callers don't check -1, NUL terminate the buffer */
61+ if ( len > 0 )
62+ buf [ 0 ] = '\0' ;
5563
56- if (flags & HN_DIVISOR_1000 ) {
57- /* SI for decimal multiplies */
58- divisor = 1000 ;
59- if (flags & HN_B )
60- prefixes = "B\0k\0M\0G\0T\0P\0E" ;
61- else
62- prefixes = "\0\0k\0M\0G\0T\0P\0E" ;
63- } else {
64+ /* validate args */
65+ if (buf == NULL || suffix == NULL )
66+ return (-1 );
67+ if (scale < 0 )
68+ return (-1 );
69+ else if (scale > maxscale &&
70+ ((scale & ~(HN_AUTOSCALE |HN_GETSCALE )) != 0 ))
71+ return (-1 );
72+ if ((flags & HN_DIVISOR_1000 ) && (flags & HN_IEC_PREFIXES ))
73+ return (-1 );
74+
75+ /* setup parameters */
76+ remainder = 0 ;
77+
78+ if (flags & HN_IEC_PREFIXES ) {
79+ baselen = 2 ;
6480 /*
65- * binary multiplies
66- * XXX IEC 60027-2 recommends Ki, Mi, Gi...
81+ * Use the prefixes for power of two recommended by
82+ * the International Electrotechnical Commission
83+ * (IEC) in IEC 80000-3 (i.e. Ki, Mi, Gi...).
84+ *
85+ * HN_IEC_PREFIXES implies a divisor of 1024 here
86+ * (use of HN_DIVISOR_1000 would have triggered
87+ * an assertion earlier).
6788 */
6889 divisor = 1024 ;
90+ divisordeccut = 973 ; /* ceil(.95 * 1024) */
6991 if (flags & HN_B )
70- prefixes = "B\0K\0M\0G\0T\0P\0E " ;
92+ prefixes = "B\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei " ;
7193 else
72- prefixes = "\0\0K\0M\0G\0T\0P\0E" ;
94+ prefixes = "\0\0\0Ki\0Mi\0Gi\0Ti\0Pi\0Ei" ;
95+ } else {
96+ baselen = 1 ;
97+ if (flags & HN_DIVISOR_1000 ) {
98+ divisor = 1000 ;
99+ divisordeccut = 950 ;
100+ if (flags & HN_B )
101+ prefixes = "B\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E" ;
102+ else
103+ prefixes = "\0\0\0k\0\0M\0\0G\0\0T\0\0P\0\0E" ;
104+ } else {
105+ divisor = 1024 ;
106+ divisordeccut = 973 ; /* ceil(.95 * 1024) */
107+ if (flags & HN_B )
108+ prefixes = "B\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E" ;
109+ else
110+ prefixes = "\0\0\0K\0\0M\0\0G\0\0T\0\0P\0\0E" ;
111+ }
73112 }
74113
75- #define SCALE2PREFIX (scale ) (&prefixes[(scale) << 1])
76- maxscale = 7 ;
114+ #define SCALE2PREFIX (scale ) (&prefixes[(scale) * 3])
77115
78- if (scale >= maxscale &&
79- (scale & (HN_AUTOSCALE | HN_GETSCALE )) == 0 )
80- return (-1 );
81-
82- if (buf == NULL || suffix == NULL )
83- return (-1 );
84-
85- if (len > 0 )
86- buf [0 ] = '\0' ;
87- if (bytes < 0 ) {
116+ if (quotient < 0 ) {
88117 sign = -1 ;
89- bytes * = -100 ;
90- baselen = 3 ; /* sign, digit, prefix */
118+ quotient = - quotient ;
119+ baselen += 2 ; /* sign, digit */
91120 } else {
92121 sign = 1 ;
93- bytes *= 100 ;
94- baselen = 2 ; /* digit, prefix */
122+ baselen += 1 ; /* digit */
95123 }
96124 if (flags & HN_NOSPACE )
97125 sep = "" ;
@@ -107,37 +135,47 @@ humanize_number(char *buf, size_t len, int64_t bytes,
107135
108136 if (scale & (HN_AUTOSCALE | HN_GETSCALE )) {
109137 /* See if there is additional columns can be used. */
110- for (max = 100 , i = ( int )( len - baselen ) ; i -- > 0 ;)
138+ for (max = 1 , i = len - baselen ; i -- > 0 ;)
111139 max *= 10 ;
112140
113141 /*
114142 * Divide the number until it fits the given column.
115143 * If there will be an overflow by the rounding below,
116144 * divide once more.
117145 */
118- for (i = 0 ; bytes >= max - 50 && i < maxscale ; i ++ )
119- bytes /= divisor ;
146+ for (i = 0 ;
147+ (quotient >= max || (quotient == max - 1 &&
148+ (remainder >= divisordeccut || remainder >=
149+ divisor / 2 ))) && i < maxscale ; i ++ ) {
150+ remainder = quotient % divisor ;
151+ quotient /= divisor ;
152+ }
120153
121154 if (scale & HN_GETSCALE )
122155 return (i );
123- } else
124- for (i = 0 ; i < scale && i < maxscale ; i ++ )
125- bytes /= divisor ;
156+ } else {
157+ for (i = 0 ; i < scale && i < maxscale ; i ++ ) {
158+ remainder = quotient % divisor ;
159+ quotient /= divisor ;
160+ }
161+ }
126162
127163 /* If a value <= 9.9 after rounding and ... */
128- if (bytes < 995 && i > 0 && flags & HN_DECIMAL ) {
129- /* baselen + \0 + .N */
130- if (len < baselen + 1 + 2 )
131- return (-1 );
132- b = ((int )bytes + 5 ) / 10 ;
133- s1 = b / 10 ;
134- s2 = b % 10 ;
164+ /*
165+ * XXX - should we make sure there is enough space for the decimal
166+ * place and if not, don't do HN_DECIMAL?
167+ */
168+ if (((quotient == 9 && remainder < divisordeccut ) || quotient < 9 ) &&
169+ i > 0 && flags & HN_DECIMAL ) {
170+ s1 = (int )quotient + ((remainder * 10 + divisor / 2 ) /
171+ divisor / 10 );
172+ s2 = ((remainder * 10 + divisor / 2 ) / divisor ) % 10 ;
135173 r = snprintf (buf , len , "%d%s%d%s%s%s" ,
136174 sign * s1 , localeconv ()-> decimal_point , s2 ,
137175 sep , SCALE2PREFIX (i ), suffix );
138176 } else
139177 r = snprintf (buf , len , "%" PRId64 "%s%s%s" ,
140- sign * (( bytes + 50 ) / 100 ),
178+ sign * (quotient + ( remainder + divisor / 2 ) / divisor ),
141179 sep , SCALE2PREFIX (i ), suffix );
142180
143181 return (r );
0 commit comments