human.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /* human.c -- print human readable file size
  2. Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  14. /* Originally contributed by [email protected];
  15. --si, output block size selection, and large file support
  16. added by [email protected]. */
  17. #if HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include <sys/types.h>
  21. #include <stdio.h>
  22. #if HAVE_LIMITS_H
  23. # include <limits.h>
  24. #endif
  25. #if HAVE_STRING_H
  26. # include <string.h>
  27. #else
  28. # include <strings.h>
  29. #endif
  30. #ifndef CHAR_BIT
  31. # define CHAR_BIT 8
  32. #endif
  33. #if HAVE_STDLIB_H
  34. # include <stdlib.h>
  35. #endif
  36. #ifndef HAVE_DECL_GETENV
  37. "this configure-time declaration test was not run"
  38. #endif
  39. #if !HAVE_DECL_GETENV
  40. char *getenv ();
  41. #endif
  42. #if ENABLE_NLS
  43. # include <libintl.h>
  44. # define _(Text) gettext (Text)
  45. #else
  46. # define _(Text) Text
  47. #endif
  48. #include <argmatch.h>
  49. #include <error.h>
  50. #include <xstrtol.h>
  51. #include "human.h"
  52. static const char suffixes[] =
  53. {
  54. 0, /* not used */
  55. 'k', /* kilo */
  56. 'M', /* Mega */
  57. 'G', /* Giga */
  58. 'T', /* Tera */
  59. 'P', /* Peta */
  60. 'E', /* Exa */
  61. 'Z', /* Zetta */
  62. 'Y' /* Yotta */
  63. };
  64. /* Like human_readable_inexact, except always round to even. */
  65. char *
  66. human_readable (uintmax_t n, char *buf,
  67. int from_block_size, int output_block_size)
  68. {
  69. return human_readable_inexact (n, buf, from_block_size, output_block_size,
  70. human_round_to_even);
  71. }
  72. /* Convert N to a human readable format in BUF.
  73. N is expressed in units of FROM_BLOCK_SIZE. FROM_BLOCK_SIZE must
  74. be nonnegative.
  75. If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
  76. the output number. OUTPUT_BLOCK_SIZE must be a multiple of
  77. FROM_BLOCK_SIZE or vice versa.
  78. Use INEXACT_STYLE to determine whether to take the ceiling or floor
  79. of any result that cannot be expressed exactly.
  80. If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
  81. possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
  82. ordinary decimal format. Normally -OUTPUT_BLOCK_SIZE is either
  83. 1000 or 1024; it must be at least 2. Most people visually process
  84. strings of 3-4 digits effectively, but longer strings of digits are
  85. more prone to misinterpretation. Hence, converting to an
  86. abbreviated form usually improves readability. Use a suffix
  87. indicating which power is being used. For example, assuming
  88. -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
  89. 133456345 to 127M, 56990456345 to 53G, and so on. Numbers smaller
  90. than -OUTPUT_BLOCK_SIZE aren't modified. */
  91. char *
  92. human_readable_inexact (uintmax_t n, char *buf,
  93. int from_block_size, int output_block_size,
  94. enum human_inexact_style inexact_style)
  95. {
  96. uintmax_t amt;
  97. int base;
  98. int to_block_size;
  99. int tenths = 0;
  100. int power;
  101. char *p;
  102. /* 0 means adjusted N == AMT.TENTHS;
  103. 1 means AMT.TENTHS < adjusted N < AMT.TENTHS + 0.05;
  104. 2 means adjusted N == AMT.TENTHS + 0.05;
  105. 3 means AMT.TENTHS + 0.05 < adjusted N < AMT.TENTHS + 0.1. */
  106. int rounding = 0;
  107. if (output_block_size < 0)
  108. {
  109. base = -output_block_size;
  110. to_block_size = 1;
  111. }
  112. else
  113. {
  114. base = 0;
  115. to_block_size = output_block_size;
  116. }
  117. p = buf + LONGEST_HUMAN_READABLE;
  118. *p = '\0';
  119. #ifdef lint
  120. /* Suppress `used before initialized' warning. */
  121. power = 0;
  122. #endif
  123. /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units. */
  124. if (to_block_size <= from_block_size)
  125. {
  126. int multiplier = from_block_size / to_block_size;
  127. amt = n * multiplier;
  128. if (amt / multiplier != n)
  129. {
  130. /* Overflow occurred during multiplication. We should use
  131. multiple precision arithmetic here, but we'll be lazy and
  132. resort to floating point. This can yield answers that
  133. are slightly off. In practice it is quite rare to
  134. overflow uintmax_t, so this is good enough for now. */
  135. double damt = n * (double) multiplier;
  136. if (! base)
  137. sprintf (buf, "%.0f", damt);
  138. else
  139. {
  140. double e = 1;
  141. power = 0;
  142. do
  143. {
  144. e *= base;
  145. power++;
  146. }
  147. while (e * base <= damt && power < sizeof suffixes - 1);
  148. damt /= e;
  149. sprintf (buf, "%.1f%c", damt, suffixes[power]);
  150. if (4 < strlen (buf))
  151. sprintf (buf, "%.0f%c", damt, suffixes[power]);
  152. }
  153. return buf;
  154. }
  155. }
  156. else if (from_block_size == 0)
  157. amt = 0;
  158. else
  159. {
  160. int divisor = to_block_size / from_block_size;
  161. int r10 = (n % divisor) * 10;
  162. int r2 = (r10 % divisor) * 2;
  163. amt = n / divisor;
  164. tenths = r10 / divisor;
  165. rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
  166. }
  167. /* Use power of BASE notation if adjusted AMT is large enough. */
  168. if (base && base <= amt)
  169. {
  170. power = 0;
  171. do
  172. {
  173. int r10 = (amt % base) * 10 + tenths;
  174. int r2 = (r10 % base) * 2 + (rounding >> 1);
  175. amt /= base;
  176. tenths = r10 / base;
  177. rounding = (r2 < base
  178. ? 0 < r2 + rounding
  179. : 2 + (base < r2 + rounding));
  180. power++;
  181. }
  182. while (base <= amt && power < sizeof suffixes - 1);
  183. *--p = suffixes[power];
  184. if (amt < 10)
  185. {
  186. if (2 * (1 - (int) inexact_style)
  187. < rounding + (tenths & (inexact_style == human_round_to_even)))
  188. {
  189. tenths++;
  190. rounding = 0;
  191. if (tenths == 10)
  192. {
  193. amt++;
  194. tenths = 0;
  195. }
  196. }
  197. if (amt < 10)
  198. {
  199. *--p = '0' + tenths;
  200. *--p = '.';
  201. tenths = rounding = 0;
  202. }
  203. }
  204. }
  205. if (inexact_style == human_ceiling
  206. ? 0 < tenths + rounding
  207. : inexact_style == human_round_to_even
  208. ? 5 < tenths + (2 < rounding + (amt & 1))
  209. : /* inexact_style == human_floor */ 0)
  210. {
  211. amt++;
  212. if (amt == base && power < sizeof suffixes - 1)
  213. {
  214. *p = suffixes[power + 1];
  215. *--p = '0';
  216. *--p = '.';
  217. amt = 1;
  218. }
  219. }
  220. do
  221. *--p = '0' + (int) (amt % 10);
  222. while ((amt /= 10) != 0);
  223. return p;
  224. }
  225. /* The default block size used for output. This number may change in
  226. the future as disks get larger. */
  227. #ifndef DEFAULT_BLOCK_SIZE
  228. # define DEFAULT_BLOCK_SIZE 1024
  229. #endif
  230. static char const *const block_size_args[] = { "human-readable", "si", 0 };
  231. static int const block_size_types[] = { -1024, -1000 };
  232. static int
  233. default_block_size (void)
  234. {
  235. return getenv ("POSIXLY_CORRECT") ? 512 : DEFAULT_BLOCK_SIZE;
  236. }
  237. static strtol_error
  238. humblock (char const *spec, int *block_size)
  239. {
  240. int i;
  241. if (! spec && ! (spec = getenv ("BLOCK_SIZE")))
  242. *block_size = default_block_size ();
  243. else if (0 <= (i = ARGMATCH (spec, block_size_args, block_size_types)))
  244. *block_size = block_size_types[i];
  245. else
  246. {
  247. char *ptr;
  248. unsigned long val;
  249. strtol_error e = xstrtoul (spec, &ptr, 0, &val, "eEgGkKmMpPtTyYzZ0");
  250. if (e != LONGINT_OK)
  251. return e;
  252. if (*ptr)
  253. return LONGINT_INVALID_SUFFIX_CHAR;
  254. if ((int) val < 0 || val != (int) val)
  255. return LONGINT_OVERFLOW;
  256. *block_size = (int) val;
  257. }
  258. return LONGINT_OK;
  259. }
  260. void
  261. human_block_size (char const *spec, int report_errors, int *block_size)
  262. {
  263. strtol_error e = humblock (spec, block_size);
  264. if (*block_size == 0)
  265. {
  266. *block_size = default_block_size ();
  267. e = LONGINT_INVALID;
  268. }
  269. if (e != LONGINT_OK && report_errors)
  270. STRTOL_FATAL_ERROR (spec, _("block size"), e);
  271. }