1 1.1 nonaka /* $NetBSD: humanize_bignum.c,v 1.1 2017/02/13 11:16:46 nonaka Exp $ */ 2 1.1 nonaka /* NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp */ 3 1.1 nonaka 4 1.1 nonaka /* 5 1.1 nonaka * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. 6 1.1 nonaka * All rights reserved. 7 1.1 nonaka * 8 1.1 nonaka * This code is derived from software contributed to The NetBSD Foundation 9 1.1 nonaka * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10 1.1 nonaka * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson. 11 1.1 nonaka * 12 1.1 nonaka * Redistribution and use in source and binary forms, with or without 13 1.1 nonaka * modification, are permitted provided that the following conditions 14 1.1 nonaka * are met: 15 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 16 1.1 nonaka * notice, this list of conditions and the following disclaimer. 17 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 19 1.1 nonaka * documentation and/or other materials provided with the distribution. 20 1.1 nonaka * 21 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 nonaka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 nonaka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 nonaka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 nonaka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 nonaka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 nonaka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 nonaka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 nonaka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 nonaka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 nonaka * POSSIBILITY OF SUCH DAMAGE. 32 1.1 nonaka */ 33 1.1 nonaka 34 1.1 nonaka #include <sys/cdefs.h> 35 1.1 nonaka 36 1.1 nonaka #include <assert.h> 37 1.1 nonaka #include <inttypes.h> 38 1.1 nonaka #include <stdio.h> 39 1.1 nonaka #include <stdlib.h> 40 1.1 nonaka #include <string.h> 41 1.1 nonaka #include <locale.h> 42 1.1 nonaka 43 1.1 nonaka #include "bn.h" 44 1.1 nonaka 45 1.1 nonaka static const BIGNUM * 46 1.1 nonaka BN_value_5(void) 47 1.1 nonaka { 48 1.1 nonaka static mp_digit digit = 5UL; 49 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 50 1.1 nonaka return &bn; 51 1.1 nonaka } 52 1.1 nonaka 53 1.1 nonaka static const BIGNUM * 54 1.1 nonaka BN_value_10(void) 55 1.1 nonaka { 56 1.1 nonaka static mp_digit digit = 10UL; 57 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 58 1.1 nonaka return &bn; 59 1.1 nonaka } 60 1.1 nonaka 61 1.1 nonaka static const BIGNUM * 62 1.1 nonaka BN_value_50(void) 63 1.1 nonaka { 64 1.1 nonaka static mp_digit digit = 50UL; 65 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 66 1.1 nonaka return &bn; 67 1.1 nonaka } 68 1.1 nonaka 69 1.1 nonaka static const BIGNUM * 70 1.1 nonaka BN_value_100(void) 71 1.1 nonaka { 72 1.1 nonaka static mp_digit digit = 100UL; 73 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 74 1.1 nonaka return &bn; 75 1.1 nonaka } 76 1.1 nonaka 77 1.1 nonaka static const BIGNUM * 78 1.1 nonaka BN_value_995(void) 79 1.1 nonaka { 80 1.1 nonaka static mp_digit digit = 995UL; 81 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 82 1.1 nonaka return &bn; 83 1.1 nonaka } 84 1.1 nonaka 85 1.1 nonaka static const BIGNUM * 86 1.1 nonaka BN_value_1000(void) 87 1.1 nonaka { 88 1.1 nonaka static mp_digit digit = 1000UL; 89 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 90 1.1 nonaka return &bn; 91 1.1 nonaka } 92 1.1 nonaka 93 1.1 nonaka static const BIGNUM * 94 1.1 nonaka BN_value_1024(void) 95 1.1 nonaka { 96 1.1 nonaka static mp_digit digit = 1024UL; 97 1.1 nonaka static const BIGNUM bn = { &digit, 1, 1, 0 }; 98 1.1 nonaka return &bn; 99 1.1 nonaka } 100 1.1 nonaka 101 1.1 nonaka int 102 1.1 nonaka humanize_bignum(char *buf, size_t len, const BIGNUM *bytes, const char *suffix, 103 1.1 nonaka int scale, int flags) 104 1.1 nonaka { 105 1.1 nonaka const char *prefixes, *sep; 106 1.1 nonaka const BIGNUM *divisor, *post; 107 1.1 nonaka BIGNUM *nbytes = NULL, *max = NULL; 108 1.1 nonaka BIGNUM *t1 = NULL, *t2 = NULL; 109 1.1 nonaka int r, sign; 110 1.1 nonaka size_t i, baselen, maxscale; 111 1.1 nonaka char *p1, *p2; 112 1.1 nonaka 113 1.1 nonaka if ((nbytes = BN_dup(bytes)) == NULL) 114 1.1 nonaka goto error; 115 1.1 nonaka 116 1.1 nonaka post = BN_value_one(); 117 1.1 nonaka 118 1.1 nonaka if (flags & HN_DIVISOR_1000) { 119 1.1 nonaka /* SI for decimal multiplies */ 120 1.1 nonaka divisor = BN_value_1000(); 121 1.1 nonaka if (flags & HN_B) 122 1.1 nonaka prefixes = "B\0k\0M\0G\0T\0P\0E\0Z\0Y"; 123 1.1 nonaka else 124 1.1 nonaka prefixes = "\0\0k\0M\0G\0T\0P\0E\0Z\0Y"; 125 1.1 nonaka } else { 126 1.1 nonaka /* 127 1.1 nonaka * binary multiplies 128 1.1 nonaka * XXX IEC 60027-2 recommends Ki, Mi, Gi... 129 1.1 nonaka */ 130 1.1 nonaka divisor = BN_value_1024(); 131 1.1 nonaka if (flags & HN_B) 132 1.1 nonaka prefixes = "B\0K\0M\0G\0T\0P\0E\0Z\0Y"; 133 1.1 nonaka else 134 1.1 nonaka prefixes = "\0\0K\0M\0G\0T\0P\0E\0Z\0Y"; 135 1.1 nonaka } 136 1.1 nonaka 137 1.1 nonaka #define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) 138 1.1 nonaka maxscale = 9; 139 1.1 nonaka 140 1.1 nonaka if ((size_t)scale >= maxscale && 141 1.1 nonaka (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) 142 1.1 nonaka goto error; 143 1.1 nonaka 144 1.1 nonaka if (buf == NULL || suffix == NULL) 145 1.1 nonaka goto error; 146 1.1 nonaka 147 1.1 nonaka if (len > 0) 148 1.1 nonaka buf[0] = '\0'; 149 1.1 nonaka if (BN_is_negative(nbytes)) { 150 1.1 nonaka sign = -1; 151 1.1 nonaka baselen = 3; /* sign, digit, prefix */ 152 1.1 nonaka BN_set_negative(nbytes, 0); 153 1.1 nonaka } else { 154 1.1 nonaka sign = 1; 155 1.1 nonaka baselen = 2; /* digit, prefix */ 156 1.1 nonaka } 157 1.1 nonaka if ((t1 = BN_new()) == NULL) 158 1.1 nonaka goto error; 159 1.1 nonaka BN_mul(t1, nbytes, BN_value_100(), NULL); 160 1.1 nonaka BN_swap(nbytes, t1); 161 1.1 nonaka 162 1.1 nonaka if (flags & HN_NOSPACE) 163 1.1 nonaka sep = ""; 164 1.1 nonaka else { 165 1.1 nonaka sep = " "; 166 1.1 nonaka baselen++; 167 1.1 nonaka } 168 1.1 nonaka baselen += strlen(suffix); 169 1.1 nonaka 170 1.1 nonaka /* Check if enough room for `x y' + suffix + `\0' */ 171 1.1 nonaka if (len < baselen + 1) 172 1.1 nonaka goto error; 173 1.1 nonaka 174 1.1 nonaka if ((t2 = BN_new()) == NULL) 175 1.1 nonaka goto error; 176 1.1 nonaka 177 1.1 nonaka if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { 178 1.1 nonaka /* See if there is additional columns can be used. */ 179 1.1 nonaka if ((max = BN_new()) == NULL) 180 1.1 nonaka goto error; 181 1.1 nonaka BN_copy(max, BN_value_100()); 182 1.1 nonaka for (i = len - baselen; i-- > 0;) { 183 1.1 nonaka BN_mul(t1, max, BN_value_10(), NULL); 184 1.1 nonaka BN_swap(max, t1); 185 1.1 nonaka } 186 1.1 nonaka 187 1.1 nonaka /* 188 1.1 nonaka * Divide the number until it fits the given column. 189 1.1 nonaka * If there will be an overflow by the rounding below, 190 1.1 nonaka * divide once more. 191 1.1 nonaka */ 192 1.1 nonaka if (BN_sub(t1, max, BN_value_50()) == 0) 193 1.1 nonaka goto error; 194 1.1 nonaka BN_swap(max, t1); 195 1.1 nonaka for (i = 0; BN_cmp(nbytes, max) >= 0 && i < maxscale; i++) { 196 1.1 nonaka if (BN_div(t1, t2, nbytes, divisor, NULL) == 0) 197 1.1 nonaka goto error; 198 1.1 nonaka BN_swap(nbytes, t1); 199 1.1 nonaka if (i == maxscale - 1) 200 1.1 nonaka break; 201 1.1 nonaka } 202 1.1 nonaka 203 1.1 nonaka if (scale & HN_GETSCALE) { 204 1.1 nonaka r = (int)i; 205 1.1 nonaka goto out; 206 1.1 nonaka } 207 1.1 nonaka } else { 208 1.1 nonaka for (i = 0; i < (size_t)scale && i < maxscale; i++) { 209 1.1 nonaka if (BN_div(t1, t2, nbytes, divisor, NULL) == 0) 210 1.1 nonaka goto error; 211 1.1 nonaka BN_swap(nbytes, t1); 212 1.1 nonaka if (i == maxscale - 1) 213 1.1 nonaka break; 214 1.1 nonaka } 215 1.1 nonaka } 216 1.1 nonaka if (BN_mul(t1, nbytes, post, NULL) == 0) 217 1.1 nonaka goto error; 218 1.1 nonaka BN_swap(nbytes, t1); 219 1.1 nonaka 220 1.1 nonaka /* If a value <= 9.9 after rounding and ... */ 221 1.1 nonaka if (BN_cmp(nbytes, __UNCONST(BN_value_995())) < 0 && 222 1.1 nonaka i > 0 && 223 1.1 nonaka (flags & HN_DECIMAL)) { 224 1.1 nonaka /* baselen + \0 + .N */ 225 1.1 nonaka if (len < baselen + 1 + 2) 226 1.1 nonaka return -1; 227 1.1 nonaka 228 1.1 nonaka if (BN_add(t1, nbytes, BN_value_5()) == 0) 229 1.1 nonaka goto error; 230 1.1 nonaka BN_swap(nbytes, t1); 231 1.1 nonaka if (BN_div(t1, t2, nbytes, BN_value_10(), NULL) == 0) 232 1.1 nonaka goto error; 233 1.1 nonaka BN_swap(nbytes, t1); 234 1.1 nonaka if (BN_div(t1, t2, nbytes, BN_value_10(), NULL) == 0) 235 1.1 nonaka goto error; 236 1.1 nonaka 237 1.1 nonaka if (sign == -1) 238 1.1 nonaka BN_set_negative(t1, 1); 239 1.1 nonaka p1 = BN_bn2dec(t1); 240 1.1 nonaka p2 = BN_bn2dec(t2); 241 1.1 nonaka if (p1 == NULL || p2 == NULL) { 242 1.1 nonaka free(p2); 243 1.1 nonaka free(p1); 244 1.1 nonaka goto error; 245 1.1 nonaka } 246 1.1 nonaka r = snprintf(buf, len, "%s%s%s%s%s%s", 247 1.1 nonaka p1, localeconv()->decimal_point, p2, 248 1.1 nonaka sep, SCALE2PREFIX(i), suffix); 249 1.1 nonaka free(p2); 250 1.1 nonaka free(p1); 251 1.1 nonaka } else { 252 1.1 nonaka if (BN_add(t1, nbytes, BN_value_50()) == 0) 253 1.1 nonaka goto error; 254 1.1 nonaka BN_swap(nbytes, t1); 255 1.1 nonaka if (BN_div(t1, t2, nbytes, BN_value_100(), NULL) == 0) 256 1.1 nonaka goto error; 257 1.1 nonaka BN_swap(nbytes, t1); 258 1.1 nonaka if (sign == -1) 259 1.1 nonaka BN_set_negative(nbytes, 1); 260 1.1 nonaka p1 = BN_bn2dec(nbytes); 261 1.1 nonaka if (p1 == NULL) 262 1.1 nonaka goto error; 263 1.1 nonaka r = snprintf(buf, len, "%s%s%s%s", 264 1.1 nonaka p1, sep, SCALE2PREFIX(i), suffix); 265 1.1 nonaka free(p1); 266 1.1 nonaka } 267 1.1 nonaka 268 1.1 nonaka out: 269 1.1 nonaka BN_free(t2); 270 1.1 nonaka BN_free(t1); 271 1.1 nonaka BN_free(max); 272 1.1 nonaka BN_free(nbytes); 273 1.1 nonaka return r; 274 1.1 nonaka 275 1.1 nonaka error: 276 1.1 nonaka r = -1; 277 1.1 nonaka goto out; 278 1.1 nonaka } 279