From: Paul Fox Date: Tue, 6 May 2014 21:28:18 +0000 (-0400) Subject: add "%(units)" function, to express numbers with SI units X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/ea781c2e172139fd1372f75e671f349689679a83 add "%(units)" function, to express numbers with SI units i.e., 1510 --> 1.5K, 15780000 --> 15.8M etc. useful with %(size), as in %(units(size)). --- diff --git a/h/fmt_compile.h b/h/fmt_compile.h index 84f7fa40..08eb8d67 100644 --- a/h/fmt_compile.h +++ b/h/fmt_compile.h @@ -44,65 +44,66 @@ #define FT_LS_WEEKDAY 35 /* set "str" to long tws weekday */ #define FT_LS_822DATE 36 /* set "str" to 822 date str */ #define FT_LS_PRETTY 37 /* set "str" to pretty (?) date str */ -#define FT_LV_SEC 38 /* set "value" to tws second */ -#define FT_LV_MIN 39 /* set "value" to tws minute */ -#define FT_LV_HOUR 40 /* set "value" to tws hour */ -#define FT_LV_MDAY 41 /* set "value" to tws day of month */ -#define FT_LV_MON 42 /* set "value" to tws month */ -#define FT_LV_YEAR 43 /* set "value" to tws year */ -#define FT_LV_YDAY 44 /* set "value" to tws day of year */ -#define FT_LV_WDAY 45 /* set "value" to tws weekday */ -#define FT_LV_ZONE 46 /* set "value" to tws timezone */ -#define FT_LV_CLOCK 47 /* set "value" to tws clock */ -#define FT_LV_RCLOCK 48 /* set "value" to now - tws clock */ -#define FT_LV_DAYF 49 /* set "value" to tws day flag */ -#define FT_LV_DST 50 /* set "value" to tws daylight savings flag */ -#define FT_LV_ZONEF 51 /* set "value" to tws timezone flag */ +#define FT_LS_UNITS 38 /* set "str" to "[KMGT]" */ +#define FT_LV_SEC 39 /* set "value" to tws second */ +#define FT_LV_MIN 40 /* set "value" to tws minute */ +#define FT_LV_HOUR 41 /* set "value" to tws hour */ +#define FT_LV_MDAY 42 /* set "value" to tws day of month */ +#define FT_LV_MON 43 /* set "value" to tws month */ +#define FT_LV_YEAR 44 /* set "value" to tws year */ +#define FT_LV_YDAY 45 /* set "value" to tws day of year */ +#define FT_LV_WDAY 46 /* set "value" to tws weekday */ +#define FT_LV_ZONE 47 /* set "value" to tws timezone */ +#define FT_LV_CLOCK 48 /* set "value" to tws clock */ +#define FT_LV_RCLOCK 49 /* set "value" to now - tws clock */ +#define FT_LV_DAYF 50 /* set "value" to tws day flag */ +#define FT_LV_DST 51 /* set "value" to tws daylight savings flag */ +#define FT_LV_ZONEF 52 /* set "value" to tws timezone flag */ -#define FT_LS_PERS 52 /* set "str" to person part of addr */ -#define FT_LS_MBOX 53 /* set "str" to mbox part of addr */ -#define FT_LS_HOST 54 /* set "str" to host part of addr */ -#define FT_LS_PATH 55 /* set "str" to route part of addr */ -#define FT_LS_GNAME 56 /* set "str" to group part of addr */ -#define FT_LS_NOTE 57 /* set "str" to comment part of addr */ -#define FT_LS_ADDR 58 /* set "str" to mbox@host */ -#define FT_LS_822ADDR 59 /* set "str" to 822 format addr */ -#define FT_LS_FRIENDLY 60 /* set "str" to "friendly" format addr */ -#define FT_LV_HOSTTYPE 61 /* set "value" to addr host type */ -#define FT_LV_INGRPF 62 /* set "value" to addr in-group flag */ -#define FT_LS_UNQUOTE 63 /* remove RFC 2822 quotes from "str" */ -#define FT_LV_NOHOSTF 64 /* set "value" to addr no-host flag */ +#define FT_LS_PERS 53 /* set "str" to person part of addr */ +#define FT_LS_MBOX 54 /* set "str" to mbox part of addr */ +#define FT_LS_HOST 55 /* set "str" to host part of addr */ +#define FT_LS_PATH 56 /* set "str" to route part of addr */ +#define FT_LS_GNAME 57 /* set "str" to group part of addr */ +#define FT_LS_NOTE 58 /* set "str" to comment part of addr */ +#define FT_LS_ADDR 59 /* set "str" to mbox@host */ +#define FT_LS_822ADDR 60 /* set "str" to 822 format addr */ +#define FT_LS_FRIENDLY 61 /* set "str" to "friendly" format addr */ +#define FT_LV_HOSTTYPE 62 /* set "value" to addr host type */ +#define FT_LV_INGRPF 63 /* set "value" to addr in-group flag */ +#define FT_LS_UNQUOTE 64 /* remove RFC 2822 quotes from "str" */ +#define FT_LV_NOHOSTF 65 /* set "value" to addr no-host flag */ /* Date Coercion */ -#define FT_LOCALDATE 65 /* Coerce date to local timezone */ -#define FT_GMTDATE 66 /* Coerce date to gmt */ +#define FT_LOCALDATE 66 /* Coerce date to local timezone */ +#define FT_GMTDATE 67 /* Coerce date to gmt */ /* pre-format processing */ -#define FT_PARSEDATE 67 /* parse comp into a date (tws) struct */ -#define FT_PARSEADDR 68 /* parse comp into a mailaddr struct */ -#define FT_FORMATADDR 69 /* let external routine format addr */ -#define FT_CONCATADDR 70 /* formataddr w/out duplicate removal */ -#define FT_MYMBOX 71 /* do "mymbox" test on comp */ +#define FT_PARSEDATE 68 /* parse comp into a date (tws) struct */ +#define FT_PARSEADDR 69 /* parse comp into a mailaddr struct */ +#define FT_FORMATADDR 70 /* let external routine format addr */ +#define FT_CONCATADDR 71 /* formataddr w/out duplicate removal */ +#define FT_MYMBOX 72 /* do "mymbox" test on comp */ /* conditionals & control flow (must be last) */ -#define FT_SAVESTR 72 /* save current str reg */ -#define FT_DONE 73 /* stop formatting */ -#define FT_PAUSE 74 /* pause */ -#define FT_NOP 75 /* nop */ -#define FT_GOTO 76 /* (relative) goto */ -#define FT_IF_S_NULL 77 /* test if "str" null */ -#define FT_IF_S 78 /* test if "str" non-null */ -#define FT_IF_V_EQ 79 /* test if "value" = literal */ -#define FT_IF_V_NE 80 /* test if "value" != literal */ -#define FT_IF_V_GT 81 /* test if "value" > literal */ -#define FT_IF_MATCH 82 /* test if "str" contains literal */ -#define FT_IF_AMATCH 83 /* test if "str" starts with literal */ -#define FT_S_NULL 84 /* V = 1 if "str" null */ -#define FT_S_NONNULL 85 /* V = 1 if "str" non-null */ -#define FT_V_EQ 86 /* V = 1 if "value" = literal */ -#define FT_V_NE 87 /* V = 1 if "value" != literal */ -#define FT_V_GT 88 /* V = 1 if "value" > literal */ -#define FT_V_MATCH 89 /* V = 1 if "str" contains literal */ -#define FT_V_AMATCH 90 /* V = 1 if "str" starts with literal */ +#define FT_SAVESTR 73 /* save current str reg */ +#define FT_DONE 74 /* stop formatting */ +#define FT_PAUSE 75 /* pause */ +#define FT_NOP 76 /* nop */ +#define FT_GOTO 77 /* (relative) goto */ +#define FT_IF_S_NULL 78 /* test if "str" null */ +#define FT_IF_S 79 /* test if "str" non-null */ +#define FT_IF_V_EQ 80 /* test if "value" = literal */ +#define FT_IF_V_NE 81 /* test if "value" != literal */ +#define FT_IF_V_GT 82 /* test if "value" > literal */ +#define FT_IF_MATCH 83 /* test if "str" contains literal */ +#define FT_IF_AMATCH 84 /* test if "str" starts with literal */ +#define FT_S_NULL 85 /* V = 1 if "str" null */ +#define FT_S_NONNULL 86 /* V = 1 if "str" non-null */ +#define FT_V_EQ 87 /* V = 1 if "value" = literal */ +#define FT_V_NE 88 /* V = 1 if "value" != literal */ +#define FT_V_GT 89 /* V = 1 if "value" > literal */ +#define FT_V_MATCH 90 /* V = 1 if "str" contains literal */ +#define FT_V_AMATCH 91 /* V = 1 if "str" starts with literal */ #define IF_FUNCS FT_S_NULL /* start of "if" functions */ diff --git a/man/mh-format.man b/man/mh-format.man index 5610a9a5..4dfa2632 100644 --- a/man/mh-format.man +++ b/man/mh-format.man @@ -290,6 +290,7 @@ decode expr string decode \fIstr\fR as RFC 2047 (MIME-encoded) component unquote expr string remove RFC 2822 quotes from \fIstr\fR trim expr trim trailing whitespace from \fIstr\fR +units expr string convert number to SI units ("15.1K") putstr expr print \fIstr\fR putstrf expr print \fIstr\fR in a fixed width putnum expr print \fInum\fR diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 3f170f31..200d738d 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -159,6 +159,7 @@ static struct ftable functable[] = { { "decodecomp", TF_COMP, FT_LS_DECODECOMP, 0, TFL_PUTS }, { "decode", TF_EXPR, FT_LS_DECODE, 0, TFL_PUTS }, { "trim", TF_EXPR, FT_LS_TRIM, 0, 0 }, + { "units", TF_EXPR, FT_LS_UNITS, 0, TFL_PUTS }, { "compval", TF_COMP, FT_LV_COMP, 0, TFL_PUTN }, { "compflag", TF_COMP, FT_LV_COMPFLAG, 0, TFL_PUTN }, { "num", TF_NUM, FT_LV_LIT, 0, TFL_PUTN }, diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index e4d79d57..c8cdece5 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -490,6 +490,41 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat, cp += n; } break; + case FT_LS_UNITS: + { + char *unitcp; + unsigned int whole, tenths; + + if (value < 1000) { + snprintf(buffer, sizeof(buffer), "%u", value); + } else { + + /* find correct scale for size (Kilo/Mega/Giga/Tera) */ + for (unitcp = "KMGT"; value > 999999; value /= 1000) { + if (!*++unitcp) + break; + } + + if (!*unitcp) { + strcpy(buffer, "huge"); + } else { + /* round up to next higer tenth of kilo-/mega-/giga- */ + value += 99; value /= 100; + + /* want one digit after decimal, avoid float */ + whole = value / 10; + tenths = value - (whole * 10); + + if (tenths) { + snprintf(buffer, sizeof(buffer), "%u.%u%c", whole, tenths, *unitcp); + } else { + snprintf(buffer, sizeof(buffer), "%u%c", whole, *unitcp); + } + } + } + str = buffer; + } + break; case FT_NUMF: cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp); break; diff --git a/uip/fmtdump.c b/uip/fmtdump.c index f1df6f35..7ee5d376 100644 --- a/uip/fmtdump.c +++ b/uip/fmtdump.c @@ -371,6 +371,7 @@ f_typestr(int t) case FT_LV_DIVIDE_L: return("LV_DIVIDE_L"); case FT_LV_MODULO_L: return("LV_MODULO_L"); case FT_LV_CHAR_LEFT: return("LV_CHAR_LEFT"); + case FT_LS_UNITS: return("LS_UNITS"); case FT_LS_MONTH: return("LS_MONTH"); case FT_LS_LMONTH: return("LS_LMONTH"); case FT_LS_ZONE: return("LS_ZONE");