HelenOS sources
This source file includes following definitions.
- capa_from_blocks
- capa_to_blocks
- capa_simplify
- capa_format
- capa_digit_val
- capa_parse
#include <assert.h>
#include <capa.h>
#include <errno.h>
#include <imath.h>
#include <stddef.h>
#include <stdio.h>
#include <str.h>
enum {
scapa_max_idig = 3,
scapa_max_sdig = 4
};
static const char *cu_str[] = {
[cu_byte] = "B",
[cu_kbyte] = "kB",
[cu_mbyte] = "MB",
[cu_gbyte] = "GB",
[cu_tbyte] = "TB",
[cu_pbyte] = "PB",
[cu_ebyte] = "EB",
[cu_zbyte] = "ZB",
[cu_ybyte] = "YB"
};
void capa_from_blocks(uint64_t nblocks, size_t block_size, capa_spec_t *capa)
{
uint64_t tsize;
tsize = nblocks * block_size;
capa->m = tsize;
capa->dp = 0;
capa->cunit = cu_byte;
}
errno_t capa_to_blocks(capa_spec_t *capa, capa_vsel_t cvsel, size_t block_size,
uint64_t *rblocks)
{
int exp;
uint64_t bytes;
uint64_t f;
uint64_t adj;
uint64_t blocks;
uint64_t rem;
errno_t rc;
exp = capa->cunit * 3 - capa->dp;
if (exp < 0) {
rc = ipow10_u64(-exp, &f);
if (rc != EOK)
return ERANGE;
bytes = (capa->m + (f / 2)) / f;
if (bytes * f - (f / 2) != capa->m)
return ERANGE;
} else {
rc = ipow10_u64(exp, &f);
if (rc != EOK)
return ERANGE;
adj = 0;
switch (cvsel) {
case cv_nom:
adj = 0;
break;
case cv_min:
adj = -(f / 2);
break;
case cv_max:
adj = f / 2 - 1;
break;
}
bytes = capa->m * f + adj;
if ((bytes - adj) / f != capa->m)
return ERANGE;
}
rem = bytes % block_size;
if ((bytes + rem) < bytes)
return ERANGE;
blocks = (bytes + rem) / block_size;
*rblocks = blocks;
return EOK;
}
void capa_simplify(capa_spec_t *capa)
{
uint64_t div;
uint64_t maxv;
unsigned sdig;
unsigned rdig;
errno_t rc;
rc = ipow10_u64(scapa_max_idig, &maxv);
assert(rc == EOK);
rc = ipow10_u64(capa->dp, &div);
assert(rc == EOK);
while (capa->m / div >= maxv) {
++capa->cunit;
capa->dp += 3;
div = div * 1000;
}
sdig = 1 + ilog10_u64(capa->m);
if (sdig > scapa_max_sdig) {
rdig = sdig - scapa_max_sdig;
if (rdig > capa->dp)
rdig = capa->dp;
rc = ipow10_u64(rdig, &div);
assert(rc == EOK);
capa->m = (capa->m + (div / 2)) / div;
capa->dp -= rdig;
}
rc = ipow10_u64(capa->dp, &div);
assert(rc == EOK);
if (capa->m / div >= 1000) {
++capa->cunit;
capa->dp += 3;
capa->m = (capa->m + 5) / 10;
--capa->dp;
}
}
errno_t capa_format(capa_spec_t *capa, char **rstr)
{
errno_t rc;
int ret;
const char *sunit;
uint64_t ipart;
uint64_t fpart;
uint64_t div;
sunit = NULL;
assert(capa->cunit < CU_LIMIT);
rc = ipow10_u64(capa->dp, &div);
if (rc != EOK)
return rc;
ipart = capa->m / div;
fpart = capa->m % div;
sunit = cu_str[capa->cunit];
if (capa->dp > 0) {
ret = asprintf(rstr, "%" PRIu64 ".%0*" PRIu64 " %s", ipart,
(int)capa->dp, fpart, sunit);
} else {
ret = asprintf(rstr, "%" PRIu64 " %s", ipart, sunit);
}
if (ret < 0)
return ENOMEM;
return EOK;
}
static errno_t capa_digit_val(char c, int *val)
{
switch (c) {
case '0':
*val = 0;
break;
case '1':
*val = 1;
break;
case '2':
*val = 2;
break;
case '3':
*val = 3;
break;
case '4':
*val = 4;
break;
case '5':
*val = 5;
break;
case '6':
*val = 6;
break;
case '7':
*val = 7;
break;
case '8':
*val = 8;
break;
case '9':
*val = 9;
break;
default:
return EINVAL;
}
return EOK;
}
errno_t capa_parse(const char *str, capa_spec_t *capa)
{
const char *eptr;
const char *p;
int d;
int dp;
unsigned long m;
int i;
m = 0;
eptr = str;
while (capa_digit_val(*eptr, &d) == EOK) {
m = m * 10 + d;
++eptr;
}
if (*eptr == '.') {
++eptr;
dp = 0;
while (capa_digit_val(*eptr, &d) == EOK) {
m = m * 10 + d;
++dp;
++eptr;
}
} else {
dp = 0;
}
while (*eptr == ' ')
++eptr;
if (*eptr == '\0') {
capa->cunit = cu_byte;
} else {
for (i = 0; i < CU_LIMIT; i++) {
if (str_lcasecmp(eptr, cu_str[i],
str_length(cu_str[i])) == 0) {
p = eptr + str_size(cu_str[i]);
while (*p == ' ')
++p;
if (*p == '\0')
goto found;
}
}
return EINVAL;
found:
capa->cunit = i;
}
capa->m = m;
capa->dp = dp;
return EOK;
}
HelenOS homepage, sources at GitHub