From 162f2a7d23a18a87cad101f68ab27de057de533d Mon Sep 17 00:00:00 2001 From: Ken Hornstein Date: Thu, 12 Jan 2012 21:07:33 -0500 Subject: [PATCH] Create two new mh-format functions: %(putlit) and %(concataddr). %(putlit) outputs a string without any space compression or control character conversion %(concataddr) is just like %(formataddr), except that inside of repl there will not be any duplicate address supression. --- h/fmt_compile.h | 158 +++++++++++++++++++++++++++-------------------------- man/mh-format.man | 23 +++++++- sbr/fmt_addr.c | 5 ++ sbr/fmt_compile.c | 2 + sbr/fmt_scan.c | 11 ++++ uip/fmtdump.c | 2 + uip/replsbr.c | 27 +++++++++ 7 files changed, 148 insertions(+), 80 deletions(-) diff --git a/h/fmt_compile.h b/h/fmt_compile.h index 22be450..3cbae02 100644 --- a/h/fmt_compile.h +++ b/h/fmt_compile.h @@ -14,95 +14,97 @@ #define FT_STR 8 /* "str" as text */ #define FT_STRF 9 /* "str" as text, filled */ #define FT_STRFW 10 /* "str" as text, filled, width in "value" */ -#define FT_PUTADDR 11 /* split and print address line */ +#define FT_STRLIT 11 /* "str" as text, no space compression */ +#define FT_PUTADDR 12 /* split and print address line */ /* types that modify the "str" or "value" registers */ -#define FT_LS_COMP 12 /* set "str" to component text */ -#define FT_LS_LIT 13 /* set "str" to literal text */ -#define FT_LS_GETENV 14 /* set "str" to getenv(text) */ -#define FT_LS_CFIND 15 /* set "str" to context_find(text) */ -#define FT_LS_DECODECOMP 16 /* set "str" to decoded component text */ -#define FT_LS_DECODE 17 /* decode "str" as RFC-2047 header */ -#define FT_LS_TRIM 18 /* trim trailing white space from "str" */ -#define FT_LV_COMP 19 /* set "value" to comp (as dec. num) */ -#define FT_LV_COMPFLAG 20 /* set "value" to comp flag word */ -#define FT_LV_LIT 21 /* set "value" to literal num */ -#define FT_LV_DAT 22 /* set "value" to dat[n] */ -#define FT_LV_STRLEN 23 /* set "value" to length of "str" */ -#define FT_LV_PLUS_L 24 /* set "value" += literal */ -#define FT_LV_MINUS_L 25 /* set "value" -= literal */ -#define FT_LV_DIVIDE_L 26 /* set "value" to value / literal */ -#define FT_LV_MODULO_L 27 /* set "value" to value % literal */ -#define FT_LV_CHAR_LEFT 28 /* set "value" to char left in output */ +#define FT_LS_COMP 13 /* set "str" to component text */ +#define FT_LS_LIT 14 /* set "str" to literal text */ +#define FT_LS_GETENV 15 /* set "str" to getenv(text) */ +#define FT_LS_CFIND 16 /* set "str" to context_find(text) */ +#define FT_LS_DECODECOMP 17 /* set "str" to decoded component text */ +#define FT_LS_DECODE 18 /* decode "str" as RFC-2047 header */ +#define FT_LS_TRIM 19 /* trim trailing white space from "str" */ +#define FT_LV_COMP 20 /* set "value" to comp (as dec. num) */ +#define FT_LV_COMPFLAG 21 /* set "value" to comp flag word */ +#define FT_LV_LIT 22 /* set "value" to literal num */ +#define FT_LV_DAT 23 /* set "value" to dat[n] */ +#define FT_LV_STRLEN 24 /* set "value" to length of "str" */ +#define FT_LV_PLUS_L 25 /* set "value" += literal */ +#define FT_LV_MINUS_L 26 /* set "value" -= literal */ +#define FT_LV_DIVIDE_L 27 /* set "value" to value / literal */ +#define FT_LV_MODULO_L 28 /* set "value" to value % literal */ +#define FT_LV_CHAR_LEFT 29 /* set "value" to char left in output */ -#define FT_LS_MONTH 29 /* set "str" to tws month */ -#define FT_LS_LMONTH 30 /* set "str" to long tws month */ -#define FT_LS_ZONE 31 /* set "str" to tws timezone */ -#define FT_LS_DAY 32 /* set "str" to tws weekday */ -#define FT_LS_WEEKDAY 33 /* set "str" to long tws weekday */ -#define FT_LS_822DATE 34 /* set "str" to 822 date str */ -#define FT_LS_PRETTY 35 /* set "str" to pretty (?) date str */ -#define FT_LV_SEC 36 /* set "value" to tws second */ -#define FT_LV_MIN 37 /* set "value" to tws minute */ -#define FT_LV_HOUR 38 /* set "value" to tws hour */ -#define FT_LV_MDAY 39 /* set "value" to tws day of month */ -#define FT_LV_MON 40 /* set "value" to tws month */ -#define FT_LV_YEAR 41 /* set "value" to tws year */ -#define FT_LV_YDAY 42 /* set "value" to tws day of year */ -#define FT_LV_WDAY 43 /* set "value" to tws weekday */ -#define FT_LV_ZONE 44 /* set "value" to tws timezone */ -#define FT_LV_CLOCK 45 /* set "value" to tws clock */ -#define FT_LV_RCLOCK 46 /* set "value" to now - tws clock */ -#define FT_LV_DAYF 47 /* set "value" to tws day flag */ -#define FT_LV_DST 48 /* set "value" to tws daylight savings flag */ -#define FT_LV_ZONEF 49 /* set "value" to tws timezone flag */ +#define FT_LS_MONTH 30 /* set "str" to tws month */ +#define FT_LS_LMONTH 31 /* set "str" to long tws month */ +#define FT_LS_ZONE 32 /* set "str" to tws timezone */ +#define FT_LS_DAY 33 /* set "str" to tws weekday */ +#define FT_LS_WEEKDAY 34 /* set "str" to long tws weekday */ +#define FT_LS_822DATE 35 /* set "str" to 822 date str */ +#define FT_LS_PRETTY 36 /* set "str" to pretty (?) date str */ +#define FT_LV_SEC 37 /* set "value" to tws second */ +#define FT_LV_MIN 38 /* set "value" to tws minute */ +#define FT_LV_HOUR 39 /* set "value" to tws hour */ +#define FT_LV_MDAY 40 /* set "value" to tws day of month */ +#define FT_LV_MON 41 /* set "value" to tws month */ +#define FT_LV_YEAR 42 /* set "value" to tws year */ +#define FT_LV_YDAY 43 /* set "value" to tws day of year */ +#define FT_LV_WDAY 44 /* set "value" to tws weekday */ +#define FT_LV_ZONE 45 /* set "value" to tws timezone */ +#define FT_LV_CLOCK 46 /* set "value" to tws clock */ +#define FT_LV_RCLOCK 47 /* set "value" to now - tws clock */ +#define FT_LV_DAYF 48 /* set "value" to tws day flag */ +#define FT_LV_DST 49 /* set "value" to tws daylight savings flag */ +#define FT_LV_ZONEF 50 /* set "value" to tws timezone flag */ -#define FT_LS_PERS 50 /* set "str" to person part of addr */ -#define FT_LS_MBOX 51 /* set "str" to mbox part of addr */ -#define FT_LS_HOST 52 /* set "str" to host part of addr */ -#define FT_LS_PATH 53 /* set "str" to route part of addr */ -#define FT_LS_GNAME 54 /* set "str" to group part of addr */ -#define FT_LS_NOTE 55 /* set "str" to comment part of addr */ -#define FT_LS_ADDR 56 /* set "str" to mbox@host */ -#define FT_LS_822ADDR 57 /* set "str" to 822 format addr */ -#define FT_LS_FRIENDLY 58 /* set "str" to "friendly" format addr */ -#define FT_LV_HOSTTYPE 59 /* set "value" to addr host type */ -#define FT_LV_INGRPF 60 /* set "value" to addr in-group flag */ -#define FT_LS_UNQUOTE 61 /* remove RFC 2822 quotes from "str" */ -#define FT_LV_NOHOSTF 62 /* set "value" to addr no-host flag */ +#define FT_LS_PERS 51 /* set "str" to person part of addr */ +#define FT_LS_MBOX 52 /* set "str" to mbox part of addr */ +#define FT_LS_HOST 53 /* set "str" to host part of addr */ +#define FT_LS_PATH 54 /* set "str" to route part of addr */ +#define FT_LS_GNAME 55 /* set "str" to group part of addr */ +#define FT_LS_NOTE 56 /* set "str" to comment part of addr */ +#define FT_LS_ADDR 57 /* set "str" to mbox@host */ +#define FT_LS_822ADDR 58 /* set "str" to 822 format addr */ +#define FT_LS_FRIENDLY 59 /* set "str" to "friendly" format addr */ +#define FT_LV_HOSTTYPE 60 /* set "value" to addr host type */ +#define FT_LV_INGRPF 61 /* set "value" to addr in-group flag */ +#define FT_LS_UNQUOTE 62 /* remove RFC 2822 quotes from "str" */ +#define FT_LV_NOHOSTF 63 /* set "value" to addr no-host flag */ /* Date Coercion */ -#define FT_LOCALDATE 63 /* Coerce date to local timezone */ -#define FT_GMTDATE 64 /* Coerce date to gmt */ +#define FT_LOCALDATE 64 /* Coerce date to local timezone */ +#define FT_GMTDATE 65 /* Coerce date to gmt */ /* pre-format processing */ -#define FT_PARSEDATE 65 /* parse comp into a date (tws) struct */ -#define FT_PARSEADDR 66 /* parse comp into a mailaddr struct */ -#define FT_FORMATADDR 67 /* let external routine format addr */ -#define FT_MYMBOX 68 /* do "mymbox" test on comp */ +#define FT_PARSEDATE 66 /* parse comp into a date (tws) struct */ +#define FT_PARSEADDR 67 /* parse comp into a mailaddr struct */ +#define FT_FORMATADDR 68 /* let external routine format addr */ +#define FT_CONCATADDR 69 /* formataddr w/out duplicate removal */ +#define FT_MYMBOX 70 /* do "mymbox" test on comp */ /* misc. */ /* ADDTOSEQ only works if you include "options LBL" */ -#define FT_ADDTOSEQ 69 /* add current msg to a sequence */ +#define FT_ADDTOSEQ 71 /* add current msg to a sequence */ /* conditionals & control flow (must be last) */ -#define FT_SAVESTR 70 /* save current str reg */ -#define FT_DONE 71 /* stop formatting */ -#define FT_PAUSE 72 /* pause */ -#define FT_NOP 73 /* nop */ -#define FT_GOTO 74 /* (relative) goto */ -#define FT_IF_S_NULL 75 /* test if "str" null */ -#define FT_IF_S 76 /* test if "str" non-null */ -#define FT_IF_V_EQ 77 /* test if "value" = literal */ -#define FT_IF_V_NE 78 /* test if "value" != literal */ -#define FT_IF_V_GT 79 /* test if "value" > literal */ -#define FT_IF_MATCH 80 /* test if "str" contains literal */ -#define FT_IF_AMATCH 81 /* test if "str" starts with literal */ -#define FT_S_NULL 82 /* V = 1 if "str" null */ -#define FT_S_NONNULL 83 /* V = 1 if "str" non-null */ -#define FT_V_EQ 84 /* V = 1 if "value" = literal */ -#define FT_V_NE 85 /* V = 1 if "value" != literal */ -#define FT_V_GT 86 /* V = 1 if "value" > literal */ -#define FT_V_MATCH 87 /* V = 1 if "str" contains literal */ -#define FT_V_AMATCH 88 /* V = 1 if "str" starts with literal */ +#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 IF_FUNCS FT_S_NULL /* start of "if" functions */ diff --git a/man/mh-format.man b/man/mh-format.man index 8925b8c..c50e02f 100644 --- a/man/mh-format.man +++ b/man/mh-format.man @@ -1,5 +1,5 @@ .\" -.\" THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. +.\" %nmhwarning% .\" .TH MH-FORMAT %manext5% "%nmhdate%" MH.6.8 [%nmhversion%] .SH NAME @@ -288,9 +288,14 @@ putstrf expr print \fIstr\fR in a fixed width putnum expr print \fInum\fR putnumf expr print \fInum\fR in a fixed width .\" addtoseq literal add msg to sequence (LBL option) +putlit expr print \fIstr\fR without space compression nodate string integer Argument not a date string (0 or 1) formataddr expr append \fIarg\fR to \fIstr\fR as a (comma separated) address list +concataddr expr append \fIarg\fR to \fIstr\fR as a + (comma separated) address list, + including duplicates, + see Special Handling putaddr literal print \fIstr\fR address list with \fIarg\fR as optional label; get line width from \fInum\fR @@ -387,10 +392,24 @@ right-justification of the string within the field, with padding on the left up to the field width. The functions (\fIputnum\fR\^) and (\fIputstr\fR\^) are somewhat special: they print their result in the minimum number of characters -required, and ignore any leading field width argument. +required, and ignore any leading field width argument. The (\fIputlit\fR\^) +function outputs the exact contents of str register without any changes +such as duplicate space removal or control character conversion. .PP The available output width is kept in an internal register; any output past this width will be truncated. +.SS Special Handling +A few functions have different behavior depending on what command they are +being invoked from. +.PP +In +.BR repl +the (\fIformataddr\fR\^) function stores all email addresses encountered into +an internal cache and will use this cache to suppress duplicate addresses. +If you need to create an address list that includes previously-seen +addresses you may use the (\fIconcataddr\fR\^) function, which is identical +to (\fIformataddr\fR\^) in all other respects. Note that (\fIconcataddr\fR\^) +will NOT add addresses to the duplicate-suppression cache. .SS Examples With all this in mind, here's the default format string for diff --git a/sbr/fmt_addr.c b/sbr/fmt_addr.c index be9b483..3186dea 100644 --- a/sbr/fmt_addr.c +++ b/sbr/fmt_addr.c @@ -112,3 +112,8 @@ formataddr (char *orig, char *str) last_dst = dst; return (buf); } + +char *concataddr (char *orig, char *str) +{ + return formataddr(orig, str); +} diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index a86661e..8368728 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -75,6 +75,7 @@ static struct ftable functable[] = { { "putnum", TF_EXPR, FT_NUM, 0, 0 }, { "putnumf", TF_EXPR, FT_NUMF, 0, 0 }, { "putaddr", TF_STR, FT_PUTADDR, 0, 0 }, + { "putlit", TF_STR, FT_STRLIT, 0, 0 }, { "void", TF_NOP, 0, 0, 0 }, { "comp", TF_COMP, FT_LS_COMP, 0, TFL_PUTS }, @@ -139,6 +140,7 @@ static struct ftable functable[] = { { "ingrp", TF_COMP, FT_LV_INGRPF, FT_PARSEADDR, TFL_PUTN }, { "nohost", TF_COMP, FT_LV_NOHOSTF, FT_PARSEADDR, TFL_PUTN }, { "formataddr", TF_EXPR_SV,FT_FORMATADDR, FT_FORMATADDR, 0 }, + { "concataddr", TF_EXPR_SV,FT_CONCATADDR, FT_FORMATADDR, 0 }, { "friendly", TF_COMP, FT_LS_FRIENDLY, FT_PARSEADDR, TFL_PUTS }, { "mymbox", TF_COMP, FT_LV_COMPFLAG, FT_MYMBOX, TFL_PUTN }, diff --git a/sbr/fmt_scan.c b/sbr/fmt_scan.c index 2bf1821..5240781 100644 --- a/sbr/fmt_scan.c +++ b/sbr/fmt_scan.c @@ -23,6 +23,7 @@ #endif extern char *formataddr (); /* hook for custom address formatting */ +extern char *concataddr (); /* address formatting but allowing duplicates */ #ifdef LBL struct msgs *fmt_current_folder; /* current folder (set by main program) */ @@ -347,6 +348,11 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) case FT_STRF: cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp); break; + case FT_STRLIT: + sp = str; + while ((c = *sp++) && cp < ep) + *cp++ = c; + break; case FT_STRFW: adios (NULL, "internal error (FT_STRFW)"); @@ -786,6 +792,11 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat) str = formataddr (savestr, str); break; + case FT_CONCATADDR: + /* The same as formataddr, but doesn't do duplicate suppression */ + str = concataddr (savestr, str); + break; + case FT_PUTADDR: /* output the str register as an address component, * splitting it into multiple lines if necessary. The diff --git a/uip/fmtdump.c b/uip/fmtdump.c index 2abf05e..6566317 100644 --- a/uip/fmtdump.c +++ b/uip/fmtdump.c @@ -354,6 +354,7 @@ f_typestr(int t) case FT_STRF: return("STRF"); case FT_STRFW: return("STRFW"); case FT_PUTADDR: return("PUTADDR"); + case FT_STRLIT: return("STRLIT"); case FT_LS_COMP: return("LS_COMP"); case FT_LS_LIT: return("LS_LIT"); case FT_LS_GETENV: return("LS_GETENV"); @@ -408,6 +409,7 @@ f_typestr(int t) case FT_PARSEDATE: return("PARSEDATE"); case FT_PARSEADDR: return("PARSEADDR"); case FT_FORMATADDR: return("FORMATADDR"); + case FT_CONCATADDR: return("CONCATADDR"); case FT_MYMBOX: return("MYMBOX"); #ifdef FT_ADDTOSEQ case FT_ADDTOSEQ: return("ADDTOSEQ"); diff --git a/uip/replsbr.c b/uip/replsbr.c index 3dda470..9ca0bb9 100644 --- a/uip/replsbr.c +++ b/uip/replsbr.c @@ -25,6 +25,7 @@ static char *badaddrs = NULL; static char *dfhost = NULL; static struct mailname mq = { NULL }; +static int nodupcheck = 0; /* If set, no check for duplicates */ /* * Buffer size for content part of header fields. @@ -380,12 +381,38 @@ formataddr (char *orig, char *str) } +/* + * fmt_scan will call this routine if the user includes the function + * "(concataddr {component})" in a format string. This behaves exactly + * like formataddr, except that it does NOT suppress duplicate addresses + * between calls. + * + * As an implementation detail: I thought about splitting out formataddr() + * into the generic part and duplicate-suppressing part, but the call to + * insert() was buried deep within a couple of loops and I didn't see a + * way to do it easily. So instead we simply set a special flag to stop + * the duplicate check and call formataddr(). + */ +char * +concataddr(char *orig, char *str) +{ + char *cp; + + nodupcheck = 1; + cp = formataddr(orig, str); + nodupcheck = 0; + return cp; +} + static int insert (struct mailname *np) { char buffer[BUFSIZ]; register struct mailname *mp; + if (nodupcheck) + return 1; + if (np->m_mbox == NULL) return 0; -- 1.7.10.4