From a9f9e3d5387e31c404fd24ee71b2a72b005b85eb Mon Sep 17 00:00:00 2001 From: Ken Hornstein Date: Mon, 8 Jul 2019 09:59:15 -0400 Subject: [PATCH] Create new mh-format function %(ordinal) Implement a new mh-format function %(ordinal). This will output the appropriate ordinal prefix (st, nd, rd, st) based on the value of the "num" register. --- docs/pending-release-notes | 3 + h/fmt_compile.h | 111 +++++++++++++++++++------------------ man/mh-format.man | 2 + sbr/fmt_compile.c | 1 + sbr/fmt_scan.c | 23 ++++++++ uip/fmtdump.c | 1 + uip/fmttest.c | 1 + 7 files changed, 87 insertions(+), 55 deletions(-) diff --git a/docs/pending-release-notes b/docs/pending-release-notes index 980ee83e..5ee7d81e 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -10,6 +10,9 @@ NEW FEATURES - inc(1)/msgchk(1) now support STARTTLS for the POP protocol. - All TLS-supported protocols now will send the SNI (server name indicator) TLS extension. +- A new mh-format function %(ordinal) has been implemented to output the + appropriate ordinal suffix for numbers. Example: "%(num 22)%(ordinal)" + will output "22nd". ----------------- OBSOLETE FEATURES diff --git a/h/fmt_compile.h b/h/fmt_compile.h index 532ccd17..470085f4 100644 --- a/h/fmt_compile.h +++ b/h/fmt_compile.h @@ -45,67 +45,68 @@ #define FT_LS_PRETTY 38 /* set "str" to pretty (?) date str */ #define FT_LS_KILO 39 /* set "str" to "[KMGT]" */ #define FT_LS_KIBI 40 /* set "str" to "[KMGT]" */ -#define FT_LV_SEC 41 /* set "value" to tws second */ -#define FT_LV_MIN 42 /* set "value" to tws minute */ -#define FT_LV_HOUR 43 /* set "value" to tws hour */ -#define FT_LV_MDAY 44 /* set "value" to tws day of month */ -#define FT_LV_MON 45 /* set "value" to tws month */ -#define FT_LV_YEAR 46 /* set "value" to tws year */ -#define FT_LV_YDAY 47 /* set "value" to tws day of year */ -#define FT_LV_WDAY 48 /* set "value" to tws weekday */ -#define FT_LV_ZONE 49 /* set "value" to tws timezone */ -#define FT_LV_CLOCK 50 /* set "value" to tws clock */ -#define FT_LV_RCLOCK 51 /* set "value" to now - tws clock */ -#define FT_LV_DAYF 52 /* set "value" to tws day flag */ -#define FT_LV_DST 53 /* set "value" to tws daylight savings flag */ -#define FT_LV_ZONEF 54 /* set "value" to tws timezone flag */ +#define FT_LS_ORDINAL 41 /* set "str" to ordinal suffix of value */ +#define FT_LV_SEC 42 /* set "value" to tws second */ +#define FT_LV_MIN 43 /* set "value" to tws minute */ +#define FT_LV_HOUR 44 /* set "value" to tws hour */ +#define FT_LV_MDAY 45 /* set "value" to tws day of month */ +#define FT_LV_MON 46 /* set "value" to tws month */ +#define FT_LV_YEAR 47 /* set "value" to tws year */ +#define FT_LV_YDAY 48 /* set "value" to tws day of year */ +#define FT_LV_WDAY 49 /* set "value" to tws weekday */ +#define FT_LV_ZONE 50 /* set "value" to tws timezone */ +#define FT_LV_CLOCK 51 /* set "value" to tws clock */ +#define FT_LV_RCLOCK 52 /* set "value" to now - tws clock */ +#define FT_LV_DAYF 53 /* set "value" to tws day flag */ +#define FT_LV_DST 54 /* set "value" to tws daylight savings flag */ +#define FT_LV_ZONEF 55 /* set "value" to tws timezone flag */ -#define FT_LS_PERS 55 /* set "str" to person part of addr */ -#define FT_LS_MBOX 56 /* set "str" to mbox part of addr */ -#define FT_LS_HOST 57 /* set "str" to host part of addr */ -#define FT_LS_PATH 58 /* set "str" to route part of addr */ -#define FT_LS_GNAME 59 /* set "str" to group part of addr */ -#define FT_LS_NOTE 60 /* set "str" to comment part of addr */ -#define FT_LS_ADDR 61 /* set "str" to mbox@host */ -#define FT_LS_822ADDR 62 /* set "str" to 822 format addr */ -#define FT_LS_FRIENDLY 63 /* set "str" to "friendly" format addr */ -#define FT_LV_HOSTTYPE 64 /* set "value" to addr host type */ -#define FT_LV_INGRPF 65 /* set "value" to addr in-group flag */ -#define FT_LS_UNQUOTE 66 /* remove RFC 2822 quotes from "str" */ -#define FT_LV_NOHOSTF 67 /* set "value" to addr no-host flag */ +#define FT_LS_PERS 56 /* set "str" to person part of addr */ +#define FT_LS_MBOX 57 /* set "str" to mbox part of addr */ +#define FT_LS_HOST 58 /* set "str" to host part of addr */ +#define FT_LS_PATH 59 /* set "str" to route part of addr */ +#define FT_LS_GNAME 60 /* set "str" to group part of addr */ +#define FT_LS_NOTE 61 /* set "str" to comment part of addr */ +#define FT_LS_ADDR 62 /* set "str" to mbox@host */ +#define FT_LS_822ADDR 63 /* set "str" to 822 format addr */ +#define FT_LS_FRIENDLY 64 /* set "str" to "friendly" format addr */ +#define FT_LV_HOSTTYPE 65 /* set "value" to addr host type */ +#define FT_LV_INGRPF 66 /* set "value" to addr in-group flag */ +#define FT_LS_UNQUOTE 67 /* remove RFC 2822 quotes from "str" */ +#define FT_LV_NOHOSTF 68 /* set "value" to addr no-host flag */ /* Date Coercion */ -#define FT_LOCALDATE 68 /* Coerce date to local timezone */ -#define FT_GMTDATE 69 /* Coerce date to GMT */ +#define FT_LOCALDATE 69 /* Coerce date to local timezone */ +#define FT_GMTDATE 70 /* Coerce date to GMT */ /* pre-format processing */ -#define FT_PARSEDATE 70 /* parse comp into a date (tws) struct */ -#define FT_PARSEADDR 71 /* parse comp into a mailaddr struct */ -#define FT_FORMATADDR 72 /* let external routine format addr */ -#define FT_CONCATADDR 73 /* formataddr w/out duplicate removal */ -#define FT_MYMBOX 74 /* do "mymbox" test on comp */ -#define FT_GETMYMBOX 75 /* return "mymbox" mailbox string */ -#define FT_GETMYADDR 76 /* return "mymbox" addr string */ +#define FT_PARSEDATE 71 /* parse comp into a date (tws) struct */ +#define FT_PARSEADDR 72 /* parse comp into a mailaddr struct */ +#define FT_FORMATADDR 73 /* let external routine format addr */ +#define FT_CONCATADDR 74 /* formataddr w/out duplicate removal */ +#define FT_MYMBOX 75 /* do "mymbox" test on comp */ +#define FT_GETMYMBOX 76 /* return "mymbox" mailbox string */ +#define FT_GETMYADDR 77 /* return "mymbox" addr string */ /* conditionals & control flow (must be last) */ -#define FT_SAVESTR 77 /* save current str reg */ -#define FT_DONE 78 /* stop formatting */ -#define FT_PAUSE 79 /* pause */ -#define FT_NOP 80 /* no-op */ -#define FT_GOTO 81 /* (relative) goto */ -#define FT_IF_S_NULL 82 /* test if "str" null */ -#define FT_IF_S 83 /* test if "str" non-null */ -#define FT_IF_V_EQ 84 /* test if "value" = literal */ -#define FT_IF_V_NE 85 /* test if "value" != literal */ -#define FT_IF_V_GT 86 /* test if "value" > literal */ -#define FT_IF_MATCH 87 /* test if "str" contains literal */ -#define FT_IF_AMATCH 88 /* test if "str" starts with literal */ -#define FT_S_NULL 89 /* V = 1 if "str" null */ -#define FT_S_NONNULL 90 /* V = 1 if "str" non-null */ -#define FT_V_EQ 91 /* V = 1 if "value" = literal */ -#define FT_V_NE 92 /* V = 1 if "value" != literal */ -#define FT_V_GT 93 /* V = 1 if "value" > literal */ -#define FT_V_MATCH 94 /* V = 1 if "str" contains literal */ -#define FT_V_AMATCH 95 /* V = 1 if "str" starts with literal */ +#define FT_SAVESTR 78 /* save current str reg */ +#define FT_DONE 79 /* stop formatting */ +#define FT_PAUSE 80 /* pause */ +#define FT_NOP 81 /* no-op */ +#define FT_GOTO 82 /* (relative) goto */ +#define FT_IF_S_NULL 83 /* test if "str" null */ +#define FT_IF_S 84 /* test if "str" non-null */ +#define FT_IF_V_EQ 85 /* test if "value" = literal */ +#define FT_IF_V_NE 86 /* test if "value" != literal */ +#define FT_IF_V_GT 87 /* test if "value" > literal */ +#define FT_IF_MATCH 88 /* test if "str" contains literal */ +#define FT_IF_AMATCH 89 /* test if "str" starts with literal */ +#define FT_S_NULL 90 /* V = 1 if "str" null */ +#define FT_S_NONNULL 91 /* V = 1 if "str" non-null */ +#define FT_V_EQ 92 /* V = 1 if "value" = literal */ +#define FT_V_NE 93 /* V = 1 if "value" != literal */ +#define FT_V_GT 94 /* V = 1 if "value" > literal */ +#define FT_V_MATCH 95 /* V = 1 if "str" contains literal */ +#define FT_V_AMATCH 96 /* 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 59972d7b..63bb04a8 100644 --- a/man/mh-format.man +++ b/man/mh-format.man @@ -290,6 +290,8 @@ kilo expr string express in SI units: 15.9K, 2.3M, etc. %(kilo) scales by factors of 1000, kibi expr string express in IEC units: 15.5Ki, 2.2Mi. %(kibi) scales by factors of 1024. +ordinal expr string Output ordinal suffix based on value + of \fInum\fR (st, nd, rd, th) 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 925a0634..97dc1fcc 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -163,6 +163,7 @@ static struct ftable functable[] = { { "trimr", TF_EXPR, FT_LS_TRIM, 0, TFL_PUTS }, { "kilo", TF_EXPR, FT_LS_KILO, 0, TFL_PUTS }, { "kibi", TF_EXPR, FT_LS_KIBI, 0, TFL_PUTS }, + { "ordinal", TF_EXPR, FT_LS_ORDINAL, 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 c75a1611..436b1ec4 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -576,6 +576,29 @@ fmt_scan (struct format *format, charstring_t scanlp, int width, int *dat, str = buffer; } break; + case FT_LS_ORDINAL: + { + int digit = value % 10; + const char *suffix; + + switch (digit) { + case 1: + suffix = "st"; + break; + case 2: + suffix = "nd"; + break; + case 3: + suffix = "rd"; + break; + default: + suffix = "th"; + } + + strncpy(buffer, suffix, sizeof(buffer)); + str = buffer; + } + break; case FT_NUMF: cpnumber (scanlp, value, fmt->f_width, fmt->f_fill, max - charstring_chars (scanlp)); diff --git a/uip/fmtdump.c b/uip/fmtdump.c index b5a4660c..18c356a5 100644 --- a/uip/fmtdump.c +++ b/uip/fmtdump.c @@ -386,6 +386,7 @@ f_typestr(int t) case FT_LS_PRETTY: return "LS_PRETTY"; case FT_LS_KILO: return "LS_KILO"; case FT_LS_KIBI: return "LS_KIBI"; + case FT_LS_ORDINAL: return "LS_ORDINAL"; case FT_LV_SEC: return "LV_SEC"; case FT_LV_MIN: return "LV_MIN"; case FT_LV_HOUR: return "LV_HOUR"; diff --git a/uip/fmttest.c b/uip/fmttest.c index 49f2104b..50804c9d 100644 --- a/uip/fmttest.c +++ b/uip/fmttest.c @@ -1083,6 +1083,7 @@ f_typestr(int t) X(LS_PRETTY); X(LS_KILO); X(LS_KIBI); + X(LS_ORDINAL); X(LV_SEC); X(LV_MIN); X(LV_HOUR); -- 2.56.0