Initial commit
[authen-passphrase-scrypt.git] / scrypt-1.2.1 / libcperciva / util / humansize.c
1 #include <stdio.h>
2
3 #include "asprintf.h"
4 #include "warnp.h"
5
6 #include "humansize.h"
7
8 /**
9 * humansize(size):
10 * Given a size in bytes, allocate and return a string of the form "<N> B"
11 * for 0 <= N <= 999 or "<X> <prefix>B" where either 10 <= X <= 999 or
12 * 1.0 <= X <= 9.9 and <prefix> is "k", "M", "G", "T", "P", or "E"; and where
13 * the value returned is the largest valid value <= the provided size.
14 */
15 char *
16 humansize(uint64_t size)
17 {
18 char * s;
19 char prefix;
20 int shiftcnt;
21 int rc;
22
23 /* Special-case for size < 1000. */
24 if (size < 1000) {
25 rc = asprintf(&s, "%d B", (int)size);
26 } else {
27 /* Keep 10 * size / 1000^(3n) in size. */
28 for (size /= 100, shiftcnt = 1; size >= 10000; shiftcnt++)
29 size /= 1000;
30
31 /*
32 * Figure out what prefix to use. Since 1 EB = 10^18 B and
33 * the maximum value of a uint64_t is 2^64 which is roughly
34 * 18.4 * 10^18, this cannot reference beyond the end of the
35 * string.
36 */
37 prefix = " kMGTPE"[shiftcnt];
38
39 /* Construct the string. */
40 if (size < 100)
41 rc = asprintf(&s, "%d.%d %cB", (int)size / 10,
42 (int)size % 10, prefix);
43 else
44 rc = asprintf(&s, "%d %cB", (int)size / 10, prefix);
45 }
46
47 if (rc == -1) {
48 warnp("asprintf");
49 goto err0;
50 }
51
52 /* Success! */
53 return (s);
54
55 err0:
56 /* Failure! */
57 return (NULL);
58 }
59
60 /**
61 * humansize_parse(s, size):
62 * Parse a string matching /[0-9]+ ?[kMGTPE]?B?/ as a size in bytes.
63 */
64 int
65 humansize_parse(const char * s, uint64_t * size)
66 {
67 int state = 0;
68 uint64_t multiplier = 1;
69
70 do {
71 switch (state) {
72 case -1:
73 /* Error state. */
74 break;
75 case 0:
76 /* Initial state. */
77 *size = 0;
78
79 /* We must start with at least one digit. */
80 if ((*s < '0') || (*s > '9')) {
81 state = -1;
82 break;
83 }
84
85 /* FALLTHROUGH */
86 case 1:
87 /* We're now processing digits. */
88 state = 1;
89
90 /* Digit-parsing state. */
91 if (('0' <= *s) && (*s <= '9')) {
92 if (*size > UINT64_MAX / 10)
93 state = -1;
94 else
95 *size *= 10;
96 if (*size > UINT64_MAX - (uint64_t)(*s - '0'))
97 state = -1;
98 else
99 *size += (uint64_t)(*s - '0');
100 break;
101 }
102
103 /* FALLTHROUGH */
104 case 2:
105 /* We move into state 3 after an optional ' '. */
106 state = 3;
107 if (*s == ' ')
108 break;
109
110 /* FALLTHROUGH */
111 case 3:
112 /* We may have one SI prefix. */
113 switch (*s) {
114 case 'E':
115 multiplier *= 1000;
116 /* FALLTHROUGH */
117 case 'P':
118 multiplier *= 1000;
119 /* FALLTHROUGH */
120 case 'T':
121 multiplier *= 1000;
122 /* FALLTHROUGH */
123 case 'G':
124 multiplier *= 1000;
125 /* FALLTHROUGH */
126 case 'M':
127 multiplier *= 1000;
128 /* FALLTHROUGH */
129 case 'k':
130 multiplier *= 1000;
131 break;
132 }
133
134 /* We move into state 4 after the optional prefix. */
135 state = 4;
136 if (multiplier != 1)
137 break;
138
139 /* FALLTHROUGH */
140 case 4:
141 /* We move into state 5 after an optional 'B'. */
142 state = 5;
143 if (*s == 'B')
144 break;
145
146 /* FALLTHROUGH */
147 case 5:
148 /* We have trailing garbage. */
149 state = -1;
150 break;
151 }
152
153 /* Move on to the next character. */
154 s++;
155 } while (*s != '\0');
156
157 /* Multiply by multiplier. */
158 if (*size > UINT64_MAX / multiplier)
159 state = -1;
160 else
161 *size *= multiplier;
162
163 /* Anything other than state -1 is success. */
164 return ((state == -1) ? -1 : 0);
165 }
This page took 0.023892 seconds and 4 git commands to generate.