humanize_bignum.c revision 1.1 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