From 44cff01e5bbe04ff991ede843e96f0c2d83d20c6 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 19 Sep 2024 18:03:17 +0200 Subject: Split into multiple C files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- fmt.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 fmt.c (limited to 'fmt.c') diff --git a/fmt.c b/fmt.c new file mode 100644 index 0000000..4c931dd --- /dev/null +++ b/fmt.c @@ -0,0 +1,189 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +static const char *units_big = "KMGTPEZYRQ"; +static const char *units_small = "munpfazyrq"; /* 'u' should be "µ" */ + + +const char * +humansize1000(off_t s, char *buf) +{ + size_t unit = 0; + if (s < 1000) { + sprintf(buf, "%u B", (unsigned)s); + return buf; + } + s /= 100; + while (units_big[unit + 1U] && s >= 10000) { + s /= 1000; + unit++; + } + sprintf(buf, "%u.%u %cB", (unsigned)s / 10U, (unsigned)s % 10U, units_big[unit]); + return buf; +} + + +const char * +humansize1024(off_t s, char *buf) +{ + size_t unit = 0; + if (s < 1024) { + sprintf(buf, "%u B", (unsigned)s); + return buf; + } + while (units_big[unit + 1U] && s >= 1024 * 1024) { + s /= 1024; + unit++; + } + sprintf(buf, "%lu.%lu %ciB", (unsigned long int)s / 1024UL, (unsigned long int)(s * 10 % 10240) / 1024UL, units_big[unit]); + return buf; +} + + +off_t +unhumansize(const char *s, char flag) +{ + off_t sum = 0, term, digit, divisor, power, base; + + if (!isdigit(s[0]) && !(s[0] == '-' && isdigit(s[1]))) + eprintf("value of -%c is not a file size", flag); + + do { + divisor = 1; + term = 0; + while (isdigit(*s)) { + digit = (*s++ & 15); + if (term > (OFF_MAX - digit) / 10) + eprintf("value of -%c option is too large", flag); + term = term * 10 + digit; + } + if (*s == '.') { + s++; + while (isdigit(*s)) { + digit = (*s++ & 15); + if (term > (OFF_MAX - digit) / 10) + eprintf("value of -%c option is too large", flag); + term = term * 10 + digit; + divisor *= 10; + } + } + + power = 0; + switch (*s) { + case 'Q': power++; /* fall through */ + case 'R': power++; /* fall through */ + case 'Y': power++; /* fall through */ + case 'Z': power++; /* fall through */ + case 'E': power++; /* fall through */ + case 'P': power++; /* fall through */ + case 'T': power++; /* fall through */ + case 'G': power++; /* fall through */ + case 'M': power++; /* fall through */ + case 'k': case 'K': power++; + if (s[1] == 'i' || s[2] == 'B') { + base = 1024; + s = &s[3]; + } else if (s[1] == 'B') { + base = 1000; + s = &s[2]; + } else { + base = 1024; + s = &s[1]; + } + while (power) { + term *= base; + power--; + } + break; + case 'B': + s++; + /* fall through */ + default: + if (divisor > 1) + eprintf("value of -%c contains non-integer exact byte count", flag); + break; + } + sum += term /= divisor; + + while (*s == ' ' || *s == ',' || *s == '+') + s++; + + } while (isdigit(s[0]) || (s[0] == '.' && isdigit(s[1]))); + + return sum; +} + + +const char * +durationstr(const struct timespec *dur, char *buf, int second_decimals) +{ + uintmax_t ss, s, m, h, d, ss_div = (uintmax_t)WHOLE_SECOND; + char *p; + const char *unit; + int i; + + if (dur->tv_sec < 0 || dur->tv_nsec < 0) + return "-"; + + if (second_decimals < 0) + second_decimals = 0; + else if (second_decimals > 9) + second_decimals = 9; + + for (i = 0; i < second_decimals; i++) + ss_div /= 10U; + ss = (uintmax_t)dur->tv_nsec / ss_div; + s = (uintmax_t)dur->tv_sec % 60U; + m = (uintmax_t)dur->tv_sec / 60U % 60U; + h = (uintmax_t)dur->tv_sec / 60U / 60U % 24U; + d = (uintmax_t)dur->tv_sec / 60U / 60U / 24U; + + p = buf; + if (d) + p += sprintf(p, "%ju days, ", d); + if (h) { + p += sprintf(p, "%ju:%02ju:%02ju", h, m, s); + unit = "hours"; + } else if (m) { + p += sprintf(p, "%ju:%02ju", m, s); + unit = "minutes"; + } else { + p += sprintf(p, "%ju", s); + unit = "seconds"; + } + if (second_decimals) + p += sprintf(p, ".%0*ju", second_decimals, ss); + p += sprintf(p, " %s", unit); + + return buf; +} + + +const char * +humanbytespersecond(double bytes_per_second, char *buf) +{ + int unit = -1; + + if (bytes_per_second < (double)0.01f) { + do { + bytes_per_second *= 1000; + unit++; + } while (units_small[unit + 1] && bytes_per_second < (double)0.01f); + if (units_small[unit] == 'u' && have_micro_symbol()) + sprintf(buf, "%.02lf µB/s", bytes_per_second); + else + sprintf(buf, "%.02lf %cB/s", bytes_per_second, units_small[unit]); + } else { + while (units_big[unit + 1] && bytes_per_second >= 1000) { + bytes_per_second /= 1000; + unit++; + } + if (unit < 0) + sprintf(buf, "%.02lf B/s", bytes_per_second); + else + sprintf(buf, "%.02lf %cB/s", bytes_per_second, units_big[unit]); + } + + return buf; +} -- cgit v1.2.3-70-g09d2