aboutsummaryrefslogtreecommitdiffstats
path: root/fmt.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-09-19 18:03:17 +0200
committerMattias Andrée <maandree@kth.se>2024-09-19 18:03:17 +0200
commit44cff01e5bbe04ff991ede843e96f0c2d83d20c6 (patch)
treef889f60eca251d716489e3b30994c435c00dbfa2 /fmt.c
parentm fixes (diff)
downloaddeadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.gz
deadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.bz2
deadshred-44cff01e5bbe04ff991ede843e96f0c2d83d20c6.tar.xz
Split into multiple C files
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
-rw-r--r--fmt.c189
1 files changed, 189 insertions, 0 deletions
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;
+}