source: mainline/uspace/lib/fdisk/src/cap.c@ 9854a8f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9854a8f was 9854a8f, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Capacity simplification, for display.

  • Property mode set to 100644
File size: 5.1 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libfdisk
30 * @{
31 */
32/**
33 * @file Disk management library.
34 */
35
36#include <errno.h>
37#include <fdisk.h>
38#include <imath.h>
39#include <stdio.h>
40#include <str.h>
41
42/** Simplified capacity parameters */
43enum {
44 /** Simplified capacity maximum integer digits */
45 scap_max_idig = 3,
46 /** Simplified capacity maximum significant digits */
47 scap_max_sdig = 4
48};
49
50static const char *cu_str[] = {
51 [cu_byte] = "B",
52 [cu_kbyte] = "kB",
53 [cu_mbyte] = "MB",
54 [cu_gbyte] = "GB",
55 [cu_tbyte] = "TB",
56 [cu_pbyte] = "PB",
57 [cu_ebyte] = "EB",
58 [cu_zbyte] = "ZB",
59 [cu_ybyte] = "YB"
60};
61
62void fdisk_cap_from_blocks(uint64_t nblocks, size_t block_size,
63 fdisk_cap_t *cap)
64{
65 uint64_t tsize;
66
67 tsize = nblocks * block_size;
68 cap->m = tsize;
69 cap->dp = 0;
70 cap->cunit = cu_byte;
71}
72
73/** Convert capacity to blocks.
74 *
75 * If the value of bytes is not integer, it is properly rounded. If the number
76 * of bytes is not divisible by the number of blocks, it is rounded
77 * up to an integer number of blocks.
78 */
79int fdisk_cap_to_blocks(fdisk_cap_t *cap, size_t block_size,
80 uint64_t *blocks)
81{
82 int exp;
83 uint64_t bytes;
84 uint64_t f;
85 int rc;
86
87 // XXX Check for overflow
88
89 exp = cap->cunit * 3 - cap->dp;
90 if (exp < 0) {
91 rc = ipow10_u64(-exp, &f);
92 if (rc != EOK)
93 return ERANGE;
94 bytes = (cap->m + (f / 2)) / f;
95 } else {
96 rc = ipow10_u64(exp, &f);
97 if (rc != EOK)
98 return ERANGE;
99 bytes = cap->m * f;
100 }
101
102 *blocks = (bytes + block_size - 1) / block_size;
103 return EOK;
104}
105
106/** Simplify and round capacity to a human-friendly form.
107 *
108 * Change unit and round the number so that we have at most three integer
109 * digits and at most two fractional digits, e.g abc.xy <unit>.
110 */
111void fdisk_cap_simplify(fdisk_cap_t *cap)
112{
113 uint64_t div;
114 uint64_t maxv;
115 unsigned sdig;
116 unsigned rdig;
117 int rc;
118
119 printf("before: m=%" PRIu64 " dp=%u cunit=%d\n",
120 cap->m, cap->dp, cap->cunit);
121
122 /* Change units so that we have at most @c scap_max_idig integer digits */
123 rc = ipow10_u64(scap_max_idig, &maxv);
124 assert(rc == EOK);
125
126 rc = ipow10_u64(cap->dp, &div);
127 assert(rc == EOK);
128
129 while (cap->m / div >= maxv) {
130 ++cap->cunit;
131 cap->dp += 3;
132 div = div * 1000;
133 }
134
135 /* Round the number so that we have at most @c scap_max_sdig significant digits */
136 sdig = 1 + ilog10_u64(cap->m); /* number of significant digits */
137 if (sdig > scap_max_sdig) {
138 /* Number of digits to remove */
139 rdig = sdig - scap_max_sdig;
140 if (rdig > cap->dp)
141 rdig = cap->dp;
142
143 rc = ipow10_u64(rdig, &div);
144 assert(rc == EOK);
145
146 cap->m = (cap->m + (div / 2)) / div;
147 cap->dp -= rdig;
148 }
149
150 printf("after: m=%" PRIu64 " dp=%u cunit=%d\n",
151 cap->m, cap->dp, cap->cunit);
152}
153
154int fdisk_cap_format(fdisk_cap_t *cap, char **rstr)
155{
156 int rc;
157 const char *sunit;
158 uint64_t ipart;
159 uint64_t fpart;
160 uint64_t div;
161
162 sunit = NULL;
163
164 if (cap->cunit < 0 || cap->cunit >= CU_LIMIT)
165 assert(false);
166
167 rc = ipow10_u64(cap->dp, &div);
168 if (rc != EOK)
169 return rc;
170
171 ipart = cap->m / div;
172 fpart = cap->m % div;
173
174 sunit = cu_str[cap->cunit];
175 if (cap->dp > 0) {
176 rc = asprintf(rstr, "%" PRIu64 ".%0*" PRIu64 " %s", ipart,
177 (int)cap->dp, fpart, sunit);
178 } else {
179 rc = asprintf(rstr, "%" PRIu64 " %s", ipart, sunit);
180 }
181 if (rc < 0)
182 return ENOMEM;
183
184 return EOK;
185}
186
187int fdisk_cap_parse(const char *str, fdisk_cap_t *cap)
188{
189 char *eptr;
190 char *p;
191 unsigned long val;
192 int i;
193
194 val = strtoul(str, &eptr, 10);
195
196 while (*eptr == ' ')
197 ++eptr;
198
199 if (*eptr == '\0') {
200 cap->cunit = cu_byte;
201 } else {
202 for (i = 0; i < CU_LIMIT; i++) {
203 if (str_lcasecmp(eptr, cu_str[i],
204 str_length(cu_str[i])) == 0) {
205 p = eptr + str_size(cu_str[i]);
206 while (*p == ' ')
207 ++p;
208 if (*p == '\0')
209 goto found;
210 }
211 }
212
213 return EINVAL;
214found:
215 cap->cunit = i;
216 }
217
218 cap->m = val;
219 cap->dp = 0;
220 return EOK;
221}
222
223/** @}
224 */
Note: See TracBrowser for help on using the repository browser.