implement field width tag format option

This implements the possibility of specifying padding for numeric tags.
Both space and zero padding is supported.
This commit is contained in:
Leonardo Gibrowski Faé 2022-12-22 16:48:27 -03:00
parent 73ccafdade
commit 146759bd96
No known key found for this signature in database
GPG key ID: 9F85F3D45A51B992
3 changed files with 79 additions and 25 deletions

View file

@ -12,6 +12,12 @@
## Unreleased ## Unreleased
### Added ### Added
* field width tag format option ([#246][246])
[246]: https://codeberg.org/dnkl/yambar/issues/246
### Changed ### Changed
* disk-io: `interval` renamed to `poll-interval` * disk-io: `interval` renamed to `poll-interval`
@ -45,6 +51,7 @@
### Security ### Security
### Contributors ### Contributors
* Leonardo Gibrowski Faé (Horus)
## 1.9.0 ## 1.9.0

View file

@ -60,10 +60,20 @@ be used.
:[ *Kind* :[ *Kind*
:[ *Description* :[ *Description*
:< *Applies to* :< *Applies to*
| [0]<number>[.]
: format
: The width reserved to the field. The leading '0' is optional and
indicates zero padding, as opposed to space padding. The trailing
'.' is also optional
: Numeric tags (integer and floats)
| .<number> | .<number>
: format : format
: How many decimals to print : How many decimals to print
: Float tags : Float tags
| [0]<N>[.]<M>
: format
: Combined version of the two previous formatters
: N: numeric tags, M: float tags
| hex | hex
: format : format
: Renders a tag's value in hex : Renders a tag's value in hex

87
tag.c
View file

@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include<errno.h>
#define LOG_MODULE "tag" #define LOG_MODULE "tag"
#define LOG_ENABLE_DBG 1 #define LOG_ENABLE_DBG 1
@ -427,13 +428,18 @@ sbuf_append(struct sbuf *s1, const char *s2)
sbuf_append_at_most(s1, s2, strlen(s2)); sbuf_append_at_most(s1, s2, strlen(s2));
} }
bool // stores the number in "*value" on success
is_number(const char *str) { static bool
while (*str != '\0') { is_number(const char *str, int *value)
if (!isdigit(*str)) {
return false; errno = 0;
++str;
} char *end;
int v = strtol(str, &end, 10);
if (errno != 0 || *end != '\0')
return false;
*value = v;
return true; return true;
} }
@ -519,8 +525,10 @@ tags_expand_template(const char *template, const struct tag_set *tags)
VALUE_UNIT, VALUE_UNIT,
} kind = VALUE_VALUE; } kind = VALUE_VALUE;
int digits = 0;
int decimals = 2; int decimals = 2;
char *float_fmt_end; bool zero_pad = false;
char *point = NULL;
for (size_t i = 0; i < MAX_TAG_ARGS; i++) { for (size_t i = 0; i < MAX_TAG_ARGS; i++) {
if (tag_args[i] == NULL) if (tag_args[i] == NULL)
@ -549,8 +557,31 @@ tags_expand_template(const char *template, const struct tag_set *tags)
kind = VALUE_MAX; kind = VALUE_MAX;
else if (strcmp(tag_args[i], "unit") == 0) else if (strcmp(tag_args[i], "unit") == 0)
kind = VALUE_UNIT; kind = VALUE_UNIT;
else if (tag_args[i][0] == '.' && is_number(tag_args[i] + 1)) else if (is_number(tag_args[i], &digits)) // i.e.: "{tag:3}"
decimals = strtol(tag_args[i] + 1, &float_fmt_end, 10); zero_pad = tag_args[i][0] == '0';
else if ((point = strchr(tag_args[i], '.')) != NULL) {
*point = '\0';
const char *digits_str = tag_args[i];
const char *decimals_str = point + 1;
if (digits_str[0] != '\0') { // guards against i.e. "{tag:.3}"
if (!is_number(digits_str, &digits)) {
LOG_WARN(
"tag `%s`: invalid field width formatter. Ignoring...",
tag_name);
}
}
if (decimals_str[0] != '\0') { // guards against i.e. "{tag:3.}"
if (!is_number(decimals_str, &decimals)) {
LOG_WARN(
"tag `%s`: invalid decimals formatter. Ignoring...",
tag_name);
}
}
zero_pad = digits_str[0] == '0';
}
else else
LOG_WARN("invalid tag formatter: %s", tag_args[i]); LOG_WARN("invalid tag formatter: %s", tag_args[i]);
} }
@ -561,8 +592,9 @@ tags_expand_template(const char *template, const struct tag_set *tags)
switch (format) { switch (format) {
case FMT_DEFAULT: { case FMT_DEFAULT: {
if (tag->type(tag) == TAG_TYPE_FLOAT){ if (tag->type(tag) == TAG_TYPE_FLOAT){
const char* fmt = zero_pad ? "%0*.*f" : "%*.*f";
char str[24]; char str[24];
snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag)); snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag));
sbuf_append(&formatted, str); sbuf_append(&formatted, str);
} else { } else {
sbuf_append(&formatted, tag->as_string(tag)); sbuf_append(&formatted, tag->as_string(tag));
@ -572,9 +604,11 @@ tags_expand_template(const char *template, const struct tag_set *tags)
case FMT_HEX: case FMT_HEX:
case FMT_OCT: { case FMT_OCT: {
const char* fmt = format == FMT_HEX ?
zero_pad ? "%0*lx" : "%*lx" :
zero_pad ? "%0*lo" : "%*lo";
char str[24]; char str[24];
snprintf(str, sizeof(str), format == FMT_HEX ? "%lx" : "%lo", snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag));
tag->as_int(tag));
sbuf_append(&formatted, str); sbuf_append(&formatted, str);
break; break;
} }
@ -584,8 +618,9 @@ tags_expand_template(const char *template, const struct tag_set *tags)
const long max = tag->max(tag); const long max = tag->max(tag);
const long cur = tag->as_int(tag); const long cur = tag->as_int(tag);
const char* fmt = zero_pad ? "%0*lu" : "%*lu";
char str[4]; char str[4];
snprintf(str, sizeof(str), "%lu", (cur - min) * 100 / (max - min)); snprintf(str, sizeof(str), fmt, digits, (cur - min) * 100 / (max - min));
sbuf_append(&formatted, str); sbuf_append(&formatted, str);
break; break;
} }
@ -606,10 +641,13 @@ tags_expand_template(const char *template, const struct tag_set *tags)
1; 1;
char str[24]; char str[24];
if (tag->type(tag) == TAG_TYPE_FLOAT) if (tag->type(tag) == TAG_TYPE_FLOAT) {
snprintf(str, sizeof(str), "%.*f", decimals, tag->as_float(tag) / (double)divider); const char* fmt = zero_pad ? "%0*.*f" : "%*.*f";
else snprintf(str, sizeof(str), fmt, digits, decimals, tag->as_float(tag) / (double)divider);
snprintf(str, sizeof(str), "%lu", tag->as_int(tag) / divider); } else {
const char* fmt = zero_pad ? "%0*lu" : "%*lu";
snprintf(str, sizeof(str), fmt, digits, tag->as_int(tag) / divider);
}
sbuf_append(&formatted, str); sbuf_append(&formatted, str);
break; break;
} }
@ -624,13 +662,12 @@ tags_expand_template(const char *template, const struct tag_set *tags)
const char *fmt; const char *fmt;
switch (format) { switch (format) {
case FMT_DEFAULT: fmt = "%ld"; break; case FMT_DEFAULT: fmt = zero_pad ? "%0*ld" : "%*ld"; break;
case FMT_HEX: fmt = "%lx"; break; case FMT_HEX: fmt = zero_pad ? "%0*lx" : "%*lx"; break;
case FMT_OCT: fmt = "%lo"; break; case FMT_OCT: fmt = zero_pad ? "%0*lo" : "%*lo"; break;
case FMT_PERCENT: case FMT_PERCENT:
value = (value - min) * 100 / (max - min); value = (value - min) * 100 / (max - min);
fmt = "%lu"; fmt = zero_pad ? "%0*lu" : "%*lu";
break; break;
case FMT_KBYTE: case FMT_KBYTE:
@ -648,13 +685,13 @@ tags_expand_template(const char *template, const struct tag_set *tags)
format == FMT_GIBYTE ? 1000 * 1000 * 1000 : format == FMT_GIBYTE ? 1000 * 1000 * 1000 :
1; 1;
value /= divider; value /= divider;
fmt = "%lu"; fmt = zero_pad ? "%0*lu" : "%*lu";
break; break;
} }
} }
char str[24]; char str[24];
snprintf(str, sizeof(str), fmt, value); snprintf(str, sizeof(str), fmt, digits, value);
sbuf_append(&formatted, str); sbuf_append(&formatted, str);
break; break;
} }