|
|
@ -18,6 +18,8 @@ convinit(void){
|
|
|
|
const char *enmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec,
|
|
|
|
const char *enmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec,
|
|
|
|
unsigned mult, int uprefix){
|
|
|
|
unsigned mult, int uprefix){
|
|
|
|
const char prefixes[] = "KMGTPEZY"; // 10^21-1 encompasses 2^64-1
|
|
|
|
const char prefixes[] = "KMGTPEZY"; // 10^21-1 encompasses 2^64-1
|
|
|
|
|
|
|
|
// FIXME can't use multibyte μ unless we enlarge the target buffer
|
|
|
|
|
|
|
|
const char subprefixes[] = "munpfazy"; // 10^24-1
|
|
|
|
unsigned consumed = 0;
|
|
|
|
unsigned consumed = 0;
|
|
|
|
uintmax_t dv;
|
|
|
|
uintmax_t dv;
|
|
|
|
|
|
|
|
|
|
|
@ -29,12 +31,22 @@ const char *enmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec,
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dv = mult;
|
|
|
|
dv = mult;
|
|
|
|
// FIXME verify that input < 2^89, wish we had static_assert() :/
|
|
|
|
if(decimal <= val || val == 0){
|
|
|
|
while((val / decimal) >= dv && consumed < strlen(prefixes)){
|
|
|
|
// FIXME verify that input < 2^89, wish we had static_assert() :/
|
|
|
|
dv *= mult;
|
|
|
|
while((val / decimal) >= dv && consumed < strlen(prefixes)){
|
|
|
|
++consumed;
|
|
|
|
dv *= mult;
|
|
|
|
if(UINTMAX_MAX / dv < mult){ // near overflow--can't scale dv again
|
|
|
|
++consumed;
|
|
|
|
break;
|
|
|
|
if(UINTMAX_MAX / dv < mult){ // near overflow--can't scale dv again
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
while(val < decimal && consumed < strlen(subprefixes)){
|
|
|
|
|
|
|
|
val *= mult;
|
|
|
|
|
|
|
|
++consumed;
|
|
|
|
|
|
|
|
if(UINTMAX_MAX / dv < mult){ // near overflow--can't scale dv again
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(dv != mult){ // if consumed == 0, dv must equal mult
|
|
|
|
if(dv != mult){ // if consumed == 0, dv must equal mult
|
|
|
@ -51,29 +63,34 @@ const char *enmetric(uintmax_t val, unsigned decimal, char *buf, int omitdec,
|
|
|
|
// 1,024). That can overflow with large 64-bit values, but we can first
|
|
|
|
// 1,024). That can overflow with large 64-bit values, but we can first
|
|
|
|
// divide both sides by mult, and then scale by 100.
|
|
|
|
// divide both sides by mult, and then scale by 100.
|
|
|
|
if(omitdec && (val % dv) == 0){
|
|
|
|
if(omitdec && (val % dv) == 0){
|
|
|
|
sprintfed = sprintf(buf, "%ju%c", val / dv,
|
|
|
|
sprintfed = sprintf(buf, "%ju%c", val / dv, prefixes[consumed - 1]);
|
|
|
|
prefixes[consumed - 1]);
|
|
|
|
|
|
|
|
}else{
|
|
|
|
}else{
|
|
|
|
uintmax_t remain = (dv == mult) ?
|
|
|
|
uintmax_t remain = (dv == mult) ?
|
|
|
|
(val % dv) * 100 / dv :
|
|
|
|
(val % dv) * 100 / dv :
|
|
|
|
((val % dv) / mult * 100) / (dv / mult);
|
|
|
|
((val % dv) / mult * 100) / (dv / mult);
|
|
|
|
sprintfed = sprintf(buf, "%ju%s%02ju%c",
|
|
|
|
sprintfed = sprintf(buf, "%ju%s%02ju%c", val / dv, decisep, remain,
|
|
|
|
val / dv,
|
|
|
|
|
|
|
|
decisep,
|
|
|
|
|
|
|
|
remain,
|
|
|
|
|
|
|
|
prefixes[consumed - 1]);
|
|
|
|
prefixes[consumed - 1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(uprefix){
|
|
|
|
if(uprefix){
|
|
|
|
buf[sprintfed] = uprefix;
|
|
|
|
buf[sprintfed] = uprefix;
|
|
|
|
buf[sprintfed + 1] = '\0';
|
|
|
|
buf[sprintfed + 1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else{ // unscaled output, consumed == 0, dv == mult
|
|
|
|
return buf;
|
|
|
|
// val / decimal < dv (or we ran out of prefixes)
|
|
|
|
}
|
|
|
|
if(omitdec && val % decimal == 0){
|
|
|
|
// unscaled output, consumed == 0, dv == mult
|
|
|
|
|
|
|
|
// val / decimal < dv (or we ran out of prefixes)
|
|
|
|
|
|
|
|
if(omitdec && val % decimal == 0){
|
|
|
|
|
|
|
|
if(consumed){
|
|
|
|
|
|
|
|
sprintf(buf, "%ju%c", val / decimal, subprefixes[consumed - 1]);
|
|
|
|
|
|
|
|
}else{
|
|
|
|
sprintf(buf, "%ju", val / decimal);
|
|
|
|
sprintf(buf, "%ju", val / decimal);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
|
|
|
|
uintmax_t divider = (decimal > mult ? decimal / mult : 1) * 10;
|
|
|
|
|
|
|
|
uintmax_t remain = (val % decimal) / divider;
|
|
|
|
|
|
|
|
if(consumed){
|
|
|
|
|
|
|
|
sprintf(buf, "%ju%s%02ju%c", val / decimal, decisep, remain, subprefixes[consumed - 1]);
|
|
|
|
}else{
|
|
|
|
}else{
|
|
|
|
uintmax_t divider = (decimal > mult ? decimal / mult : 1) * 10;
|
|
|
|
|
|
|
|
uintmax_t remain = (val % decimal) / divider;
|
|
|
|
|
|
|
|
sprintf(buf, "%ju%s%02ju", val / decimal, decisep, remain);
|
|
|
|
sprintf(buf, "%ju%s%02ju", val / decimal, decisep, remain);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|