1 /* human.c -- print human readable file size
2
3 Copyright (C) 1996-2007, 2009-2014 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18 /* Written by Paul Eggert and Larry McVoy. */
19
20 #include <config.h>
21
22 #include "human.h"
23
24 #include <locale.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <argmatch.h>
30 #include <error.h>
31 #include <intprops.h>
32
33 /* The maximum length of a suffix like "KiB". */
34 #define HUMAN_READABLE_SUFFIX_LENGTH_MAX 3
35
36 static const char power_letter[] =
37 {
38 0, /* not used */
39 'K', /* kibi ('k' for kilo is a special case) */
40 'M', /* mega or mebi */
41 'G', /* giga or gibi */
42 'T', /* tera or tebi */
43 'P', /* peta or pebi */
44 'E', /* exa or exbi */
45 'Z', /* zetta or 2**70 */
46 'Y' /* yotta or 2**80 */
47 };
48
49
50 /* If INEXACT_STYLE is not human_round_to_nearest, and if easily
51 possible, adjust VALUE according to the style. */
52
53 static long double
adjust_value(int inexact_style,long double value)54 adjust_value (int inexact_style, long double value)
55 {
56 /* Do not use the floorl or ceill functions, as that would mean
57 checking for their presence and possibly linking with the
58 standard math library, which is a porting pain. So leave the
59 value alone if it is too large to easily round. */
60 if (inexact_style != human_round_to_nearest && value < UINTMAX_MAX)
61 {
62 uintmax_t u = value;
63 value = u + (inexact_style == human_ceiling && u != value);
64 }
65
66 return value;
67 }
68
69 /* Group the digits of NUMBER according to the grouping rules of the
70 current locale. NUMBER contains NUMBERLEN digits. Modify the
71 bytes pointed to by NUMBER in place, subtracting 1 from NUMBER for
72 each byte inserted. Return the starting address of the modified
73 number.
74
75 To group the digits, use GROUPING and THOUSANDS_SEP as in 'struct
76 lconv' from <locale.h>. */
77
78 static char *
group_number(char * number,size_t numberlen,char const * grouping,char const * thousands_sep)79 group_number (char *number, size_t numberlen,
80 char const *grouping, char const *thousands_sep)
81 {
82 register char *d;
83 size_t grouplen = SIZE_MAX;
84 size_t thousands_seplen = strlen (thousands_sep);
85 size_t i = numberlen;
86
87 /* The maximum possible value for NUMBERLEN is the number of digits
88 in the square of the largest uintmax_t, so double the size needed. */
89 char buf[2 * INT_STRLEN_BOUND (uintmax_t) + 1];
90
91 memcpy (buf, number, numberlen);
92 d = number + numberlen;
93
94 for (;;)
95 {
96 unsigned char g = *grouping;
97
98 if (g)
99 {
100 grouplen = g < CHAR_MAX ? g : i;
101 grouping++;
102 }
103
104 if (i < grouplen)
105 grouplen = i;
106
107 d -= grouplen;
108 i -= grouplen;
109 memcpy (d, buf + i, grouplen);
110 if (i == 0)
111 return d;
112
113 d -= thousands_seplen;
114 memcpy (d, thousands_sep, thousands_seplen);
115 }
116 }
117
118 /* Convert N to a human readable format in BUF, using the options OPTS.
119
120 N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
121 be nonnegative.
122
123 Use units of TO_BLOCK_SIZE in the output number. TO_BLOCK_SIZE
124 must be positive.
125
126 Use (OPTS & (human_round_to_nearest | human_floor | human_ceiling))
127 to determine whether to take the ceiling or floor of any result
128 that cannot be expressed exactly.
129
130 If (OPTS & human_group_digits), group the thousands digits
131 according to the locale, e.g., "1,000,000" in an American English
132 locale.
133
134 If (OPTS & human_autoscale), deduce the output block size
135 automatically; TO_BLOCK_SIZE must be 1 but it has no effect on the
136 output. Use powers of 1024 if (OPTS & human_base_1024), and powers
137 of 1000 otherwise. For example, assuming powers of 1024, 8500
138 would be converted to 8.3, 133456345 to 127, 56990456345 to 53, and
139 so on. Numbers smaller than the power aren't modified.
140 human_autoscale is normally used together with human_SI.
141
142 If (OPTS & human_space_before_unit), use a space to separate the
143 number from any suffix that is appended as described below.
144
145 If (OPTS & human_SI), append an SI prefix indicating which power is
146 being used. If in addition (OPTS & human_B), append "B" (if base
147 1000) or "iB" (if base 1024) to the SI prefix. When ((OPTS &
148 human_SI) && ! (OPTS & human_autoscale)), TO_BLOCK_SIZE must be a
149 power of 1024 or of 1000, depending on (OPTS &
150 human_base_1024). */
151
152 char *
human_readable(uintmax_t n,char * buf,int opts,uintmax_t from_block_size,uintmax_t to_block_size)153 human_readable (uintmax_t n, char *buf, int opts,
154 uintmax_t from_block_size, uintmax_t to_block_size)
155 {
156 int inexact_style =
157 opts & (human_round_to_nearest | human_floor | human_ceiling);
158 unsigned int base = opts & human_base_1024 ? 1024 : 1000;
159 uintmax_t amt;
160 int tenths;
161 int exponent = -1;
162 int exponent_max = sizeof power_letter - 1;
163 char *p;
164 char *psuffix;
165 char const *integerlim;
166
167 /* 0 means adjusted N == AMT.TENTHS;
168 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
169 2 means adjusted N == AMT.TENTHS + 0.05;
170 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
171 int rounding;
172
173 char const *decimal_point = ".";
174 size_t decimal_pointlen = 1;
175 char const *grouping = "";
176 char const *thousands_sep = "";
177 struct lconv const *l = localeconv ();
178 size_t pointlen = strlen (l->decimal_point);
179 if (0 < pointlen && pointlen <= MB_LEN_MAX)
180 {
181 decimal_point = l->decimal_point;
182 decimal_pointlen = pointlen;
183 }
184 grouping = l->grouping;
185 if (strlen (l->thousands_sep) <= MB_LEN_MAX)
186 thousands_sep = l->thousands_sep;
187
188 psuffix = buf + LONGEST_HUMAN_READABLE - HUMAN_READABLE_SUFFIX_LENGTH_MAX;
189 p = psuffix;
190
191 /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE
192 units. If this can be done exactly with integer arithmetic, do
193 not use floating point operations. */
194 if (to_block_size <= from_block_size)
195 {
196 if (from_block_size % to_block_size == 0)
197 {
198 uintmax_t multiplier = from_block_size / to_block_size;
199 amt = n * multiplier;
200 if (amt / multiplier == n)
201 {
202 tenths = 0;
203 rounding = 0;
204 goto use_integer_arithmetic;
205 }
206 }
207 }
208 else if (from_block_size != 0 && to_block_size % from_block_size == 0)
209 {
210 uintmax_t divisor = to_block_size / from_block_size;
211 uintmax_t r10 = (n % divisor) * 10;
212 uintmax_t r2 = (r10 % divisor) * 2;
213 amt = n / divisor;
214 tenths = r10 / divisor;
215 rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
216 goto use_integer_arithmetic;
217 }
218
219 {
220 /* Either the result cannot be computed easily using uintmax_t,
221 or from_block_size is zero. Fall back on floating point.
222 FIXME: This can yield answers that are slightly off. */
223
224 long double dto_block_size = to_block_size;
225 long double damt = n * (from_block_size / dto_block_size);
226 size_t buflen;
227 size_t nonintegerlen;
228
229 if (! (opts & human_autoscale))
230 {
231 sprintf (buf, "%.0Lf", adjust_value (inexact_style, damt));
232 buflen = strlen (buf);
233 nonintegerlen = 0;
234 }
235 else
236 {
237 long double e = 1;
238 exponent = 0;
239
240 do
241 {
242 e *= base;
243 exponent++;
244 }
245 while (e * base <= damt && exponent < exponent_max);
246
247 damt /= e;
248
249 sprintf (buf, "%.1Lf", adjust_value (inexact_style, damt));
250 buflen = strlen (buf);
251 nonintegerlen = decimal_pointlen + 1;
252
253 if (1 + nonintegerlen + ! (opts & human_base_1024) < buflen
254 || ((opts & human_suppress_point_zero)
255 && buf[buflen - 1] == '0'))
256 {
257 sprintf (buf, "%.0Lf",
258 adjust_value (inexact_style, damt * 10) / 10);
259 buflen = strlen (buf);
260 nonintegerlen = 0;
261 }
262 }
263
264 p = psuffix - buflen;
265 memmove (p, buf, buflen);
266 integerlim = p + buflen - nonintegerlen;
267 }
268 goto do_grouping;
269
270 use_integer_arithmetic:
271 {
272 /* The computation can be done exactly, with integer arithmetic.
273
274 Use power of BASE notation if requested and if adjusted AMT is
275 large enough. */
276
277 if (opts & human_autoscale)
278 {
279 exponent = 0;
280
281 if (base <= amt)
282 {
283 do
284 {
285 unsigned int r10 = (amt % base) * 10 + tenths;
286 unsigned int r2 = (r10 % base) * 2 + (rounding >> 1);
287 amt /= base;
288 tenths = r10 / base;
289 rounding = (r2 < base
290 ? (r2 + rounding) != 0
291 : 2 + (base < r2 + rounding));
292 exponent++;
293 }
294 while (base <= amt && exponent < exponent_max);
295
296 if (amt < 10)
297 {
298 if (inexact_style == human_round_to_nearest
299 ? 2 < rounding + (tenths & 1)
300 : inexact_style == human_ceiling && 0 < rounding)
301 {
302 tenths++;
303 rounding = 0;
304
305 if (tenths == 10)
306 {
307 amt++;
308 tenths = 0;
309 }
310 }
311
312 if (amt < 10
313 && (tenths || ! (opts & human_suppress_point_zero)))
314 {
315 *--p = '0' + tenths;
316 p -= decimal_pointlen;
317 memcpy (p, decimal_point, decimal_pointlen);
318 tenths = rounding = 0;
319 }
320 }
321 }
322 }
323
324 if (inexact_style == human_round_to_nearest
325 ? 5 < tenths + (0 < rounding + (amt & 1))
326 : inexact_style == human_ceiling && 0 < tenths + rounding)
327 {
328 amt++;
329
330 if ((opts & human_autoscale)
331 && amt == base && exponent < exponent_max)
332 {
333 exponent++;
334 if (! (opts & human_suppress_point_zero))
335 {
336 *--p = '0';
337 p -= decimal_pointlen;
338 memcpy (p, decimal_point, decimal_pointlen);
339 }
340 amt = 1;
341 }
342 }
343
344 integerlim = p;
345
346 do
347 {
348 int digit = amt % 10;
349 *--p = digit + '0';
350 }
351 while ((amt /= 10) != 0);
352 }
353
354 do_grouping:
355 if (opts & human_group_digits)
356 p = group_number (p, integerlim - p, grouping, thousands_sep);
357
358 if (opts & human_SI)
359 {
360 if (exponent < 0)
361 {
362 uintmax_t power;
363 exponent = 0;
364 for (power = 1; power < to_block_size; power *= base)
365 if (++exponent == exponent_max)
366 break;
367 }
368
369 if ((exponent | (opts & human_B)) && (opts & human_space_before_unit))
370 *psuffix++ = ' ';
371
372 if (exponent)
373 *psuffix++ = (! (opts & human_base_1024) && exponent == 1
374 ? 'k'
375 : power_letter[exponent]);
376
377 if (opts & human_B)
378 {
379 if ((opts & human_base_1024) && exponent)
380 *psuffix++ = 'i';
381 *psuffix++ = 'B';
382 }
383 }
384
385 *psuffix = '\0';
386
387 return p;
388 }
389
390
391 /* The default block size used for output. This number may change in
392 the future as disks get larger. */
393 #ifndef DEFAULT_BLOCK_SIZE
394 # define DEFAULT_BLOCK_SIZE 1024
395 #endif
396
397 static char const *const block_size_args[] = { "human-readable", "si", 0 };
398 static int const block_size_opts[] =
399 {
400 human_autoscale + human_SI + human_base_1024,
401 human_autoscale + human_SI
402 };
403
404 static uintmax_t
default_block_size(void)405 default_block_size (void)
406 {
407 return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
408 }
409
410 static strtol_error
humblock(char const * spec,uintmax_t * block_size,int * options)411 humblock (char const *spec, uintmax_t *block_size, int *options)
412 {
413 int i;
414 int opts = 0;
415
416 if (! spec
417 && ! (spec = getenv ("BLOCK_SIZE"))
418 && ! (spec = getenv ("BLOCKSIZE")))
419 *block_size = default_block_size ();
420 else
421 {
422 if (*spec == '\'')
423 {
424 opts |= human_group_digits;
425 spec++;
426 }
427
428 if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_opts)))
429 {
430 opts |= block_size_opts[i];
431 *block_size = 1;
432 }
433 else
434 {
435 char *ptr;
436 strtol_error e = xstrtoumax (spec, &ptr, 0, block_size,
437 "eEgGkKmMpPtTyYzZ0");
438 if (e != LONGINT_OK)
439 {
440 *options = 0;
441 return e;
442 }
443 for (; ! ('0' <= *spec && *spec <= '9'); spec++)
444 if (spec == ptr)
445 {
446 opts |= human_SI;
447 if (ptr[-1] == 'B')
448 opts |= human_B;
449 if (ptr[-1] != 'B' || ptr[-2] == 'i')
450 opts |= human_base_1024;
451 break;
452 }
453 }
454 }
455
456 *options = opts;
457 return LONGINT_OK;
458 }
459
460 enum strtol_error
human_options(char const * spec,int * opts,uintmax_t * block_size)461 human_options (char const *spec, int *opts, uintmax_t *block_size)
462 {
463 strtol_error e = humblock (spec, block_size, opts);
464 if (*block_size == 0)
465 {
466 *block_size = default_block_size ();
467 e = LONGINT_INVALID;
468 }
469 return e;
470 }
471