blob: b9fc3c0fdf2c807013d4d137bcb3095e5e103699 [file] [log] [blame]
// Copyright (C) 2012 - Will Glozer. All rights reserved.
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <inttypes.h>
#include "units.h"
#include "aprintf.h"
typedef struct {
int scale;
char *base;
char *units[];
} units;
units time_units_us = {
.scale = 1000,
.base = "us",
.units = { "ms", "s", NULL }
};
units time_units_s = {
.scale = 60,
.base = "s",
.units = { "m", "h", NULL }
};
units binary_units = {
.scale = 1024,
.base = "",
.units = { "K", "M", "G", "T", "P", NULL }
};
units metric_units = {
.scale = 1000,
.base = "",
.units = { "k", "M", "G", "T", "P", NULL }
};
static char *format_units(long double n, units *m, int p) {
long double amt = n, scale;
char *unit = m->base;
char *msg = NULL;
scale = m->scale * 0.85;
for (int i = 0; m->units[i+1] && amt >= scale; i++) {
amt /= m->scale;
unit = m->units[i];
}
aprintf(&msg, "%.*Lf%s", p, amt, unit);
return msg;
}
static int scan_units(char *s, uint64_t *n, units *m) {
uint64_t base, scale = 1;
char unit[3] = { 0, 0, 0 };
int i, c;
if ((c = sscanf(s, "%"SCNu64"%2s", &base, unit)) < 1) return -1;
if (c == 2) {
for (i = 0; m->units[i] != NULL; i++) {
scale *= m->scale;
if (!strncasecmp(unit, m->units[i], sizeof(unit))) break;
}
if (m->units[i] == NULL) return -1;
}
*n = base * scale;
return 0;
}
char *format_binary(long double n) {
return format_units(n, &binary_units, 2);
}
char *format_metric(long double n) {
return format_units(n, &metric_units, 2);
}
char *format_time_us(long double n) {
units *units = &time_units_us;
if (n >= 1000000.0) {
n /= 1000000.0;
units = &time_units_s;
}
return format_units(n, units, 2);
}
int scan_metric(char *s, uint64_t *n) {
return scan_units(s, n, &metric_units);
}