source: MondoRescue/branches/3.3/mindi-busybox/libbb/human_readable.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 4.9 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
[821]2/*
3 * June 30, 2001 Manuel Novoa III
4 *
5 * All-integer version (hey, not everyone has floating point) of
6 * make_human_readable_str, modified from similar code I had written
7 * for busybox several months ago.
8 *
9 * Notes:
10 * 1) I'm using an unsigned long long to hold the product size * block_size,
11 * as df (which calls this routine) could request a representation of a
12 * partition size in bytes > max of unsigned long. If long longs aren't
13 * available, it would be possible to do what's needed using polynomial
14 * representations (say, powers of 1024) and manipulating coefficients.
15 * The base ten "bytes" output could be handled similarly.
16 *
[3621]17 * 2) This routine outputs a decimal point and a tenths digit when
18 * display_unit == 0. Hence, it isn't uncommon for the returned string
[821]19 * to have a length of 5 or 6.
20 *
[3621]21 * If block_size is also 0, no decimal digits are printed.
[821]22 *
[2725]23 * Licensed under GPLv2, see file LICENSE in this source tree.
[821]24 */
25
26#include "libbb.h"
27
[2725]28const char* FAST_FUNC make_human_readable_str(unsigned long long val,
[821]29 unsigned long block_size, unsigned long display_unit)
30{
[2725]31 static const char unit_chars[] ALIGN1 = {
32 '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'
33 };
[821]34
[2725]35 unsigned frac; /* 0..9 - the fractional digit */
[821]36 const char *u;
[2725]37 const char *fmt;
[821]38
[2725]39 if (val == 0)
40 return "0";
41
42 fmt = "%llu";
43 if (block_size > 1)
44 val *= block_size;
[821]45 frac = 0;
[2725]46 u = unit_chars;
[821]47
48 if (display_unit) {
[2725]49 val += display_unit/2; /* Deal with rounding */
50 val /= display_unit; /* Don't combine with the line above! */
51 /* will just print it as ulonglong (below) */
[821]52 } else {
[1765]53 while ((val >= 1024)
[2725]54 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */
[1765]55 ) {
[2725]56 fmt = "%llu.%u%c";
57 u++;
58 frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024;
[1765]59 val /= 1024;
[821]60 }
[2725]61 if (frac >= 10) { /* we need to round up here */
[821]62 ++val;
63 frac = 0;
64 }
[2725]65#if 1
66 /* If block_size is 0, dont print fractional part */
67 if (block_size == 0) {
[1765]68 if (frac >= 5) {
[821]69 ++val;
70 }
[2725]71 fmt = "%llu%*c";
[821]72 frac = 1;
73 }
74#endif
75 }
76
[3621]77 return auto_string(xasprintf(fmt, val, frac, *u));
[821]78}
[2725]79
80
81/* vda's implementations of the similar idea */
82
83/* Convert unsigned long long value into compact 5-char representation.
84 * String is not terminated (buf[5] is untouched) */
[3621]85char* FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale)
[2725]86{
87 const char *fmt;
88 char c;
89 unsigned v, u, idx = 0;
90
91 if (ul > 99999) { // do not scale if 99999 or less
92 ul *= 10;
93 do {
94 ul /= 1024;
95 idx++;
96 } while (ul >= 100000);
97 }
98 v = ul; // ullong divisions are expensive, avoid them
99
100 fmt = " 123456789";
101 u = v / 10;
102 v = v % 10;
103 if (!idx) {
104 // 99999 or less: use "12345" format
105 // u is value/10, v is last digit
106 c = buf[0] = " 123456789"[u/1000];
107 if (c != ' ') fmt = "0123456789";
108 c = buf[1] = fmt[u/100%10];
109 if (c != ' ') fmt = "0123456789";
110 c = buf[2] = fmt[u/10%10];
111 if (c != ' ') fmt = "0123456789";
112 buf[3] = fmt[u%10];
113 buf[4] = "0123456789"[v];
114 } else {
115 // value has been scaled into 0..9999.9 range
116 // u is value, v is 1/10ths (allows for 92.1M format)
117 if (u >= 100) {
118 // value is >= 100: use "1234M', " 123M" formats
119 c = buf[0] = " 123456789"[u/1000];
120 if (c != ' ') fmt = "0123456789";
121 c = buf[1] = fmt[u/100%10];
122 if (c != ' ') fmt = "0123456789";
123 v = u % 10;
124 u = u / 10;
125 buf[2] = fmt[u%10];
126 } else {
127 // value is < 100: use "92.1M" format
128 c = buf[0] = " 123456789"[u/10];
129 if (c != ' ') fmt = "0123456789";
130 buf[1] = fmt[u%10];
131 buf[2] = '.';
132 }
133 buf[3] = "0123456789"[v];
134 buf[4] = scale[idx]; /* typically scale = " kmgt..." */
135 }
[3621]136 return buf + 5;
[2725]137}
138
139/* Convert unsigned long long value into compact 4-char
140 * representation. Examples: "1234", "1.2k", " 27M", "123T"
141 * String is not terminated (buf[4] is untouched) */
[3621]142char* FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale)
[2725]143{
144 const char *fmt;
145 char c;
146 unsigned v, u, idx = 0;
147
148 if (ul > 9999) { // do not scale if 9999 or less
149 ul *= 10;
150 do {
151 ul /= 1024;
152 idx++;
153 } while (ul >= 10000);
154 }
155 v = ul; // ullong divisions are expensive, avoid them
156
157 fmt = " 123456789";
158 u = v / 10;
159 v = v % 10;
160 if (!idx) {
161 // 9999 or less: use "1234" format
162 // u is value/10, v is last digit
163 c = buf[0] = " 123456789"[u/100];
164 if (c != ' ') fmt = "0123456789";
165 c = buf[1] = fmt[u/10%10];
166 if (c != ' ') fmt = "0123456789";
167 buf[2] = fmt[u%10];
168 buf[3] = "0123456789"[v];
169 } else {
170 // u is value, v is 1/10ths (allows for 9.2M format)
171 if (u >= 10) {
172 // value is >= 10: use "123M', " 12M" formats
173 c = buf[0] = " 123456789"[u/100];
174 if (c != ' ') fmt = "0123456789";
175 v = u % 10;
176 u = u / 10;
177 buf[1] = fmt[u%10];
178 } else {
179 // value is < 10: use "9.2M" format
180 buf[0] = "0123456789"[u];
181 buf[1] = '.';
182 }
183 buf[2] = "0123456789"[v];
184 buf[3] = scale[idx]; /* typically scale = " kmgt..." */
185 }
[3621]186 return buf + 4;
[2725]187}
Note: See TracBrowser for help on using the repository browser.