From a263b49422590feb52789266f3e9bc89cb746b96 Mon Sep 17 00:00:00 2001 From: "Steffen (Daode) Nurpmeso" Date: Tue, 19 Apr 2016 14:20:28 +0200 Subject: [PATCH] Add n_strescsep() (allows backslash escaped separator).. P.S.: during development of v14.9 it has become clear that we will start being backward-incompatible, and support for sh(1)ell-style argument quoting has been implemented on the [topic/wysh] branch. There we've also added n_shell_sep(), which is the true successor of strsep(), as it'll allow the user to specify _exactly_ what she wants, and in a known and standardized syntax. Of course much has to change in the future to get there, but nonetheless: adding such a fragile and non-standard (but for RFC 1524) syntax, like n_strescsep(), is thus only a temporary solution. Therefore usage of this function will be removed again as far as possible during v14.9 development, and once only *customhdr* remains (which is itself temporary), we'll make this function local, to be removed in v15. --- attachments.c | 2 +- nail.1 | 10 ++++++---- nailfuns.h | 6 +++++- nam_a_grp.c | 2 +- strings.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 7 deletions(-) diff --git a/attachments.c b/attachments.c index 127a0f4e..41b4d6db 100644 --- a/attachments.c +++ b/attachments.c @@ -385,7 +385,7 @@ append_attachments(struct attachment **aphead, char *names) struct attachment *xaph, *nap; NYD_ENTER; - while ((cp = n_strsep(&names, ',', 1)) != NULL) { + while ((cp = n_strescsep(&names, ',', TRU1)) != NULL) { xaph = add_attachment(*aphead, fexpand_nshell_quote(cp), &nap); if (xaph != NULL) { *aphead = xaph; diff --git a/nail.1 b/nail.1 index 7d675b2d..a3895e24 100644 --- a/nail.1 +++ b/nail.1 @@ -4690,8 +4690,9 @@ arguments are specified for the .Ic \&\&~@ command they are treated as a comma-separated list of files, which are all expanded and appended to the end of the attachment list. -(Filenames with commas, or with leading or trailing whitespace can only -be added via the command line or the first method. +(Commas need to be escaped with backslash, but filenames with leading or +trailing whitespace can only be added via the command line or the first +method. Message attachments can only be added via the first method; filenames which clash with message numbers can only be added via the command line or the second method.) @@ -5454,9 +5455,10 @@ and \*(OB A variable counterpart of the .Ic customhdr command (see there for documentation), interpreted as a comma-separated -list of custom headers to be injected, e.g.: +list of custom headers to be injected, to include commas in the header +bodies escape them with backslash, e.g.: .Pp -.Dl set customhdr="Hdr1: Body1, Hdr2: Body2" +.Dl set customhdr="Hdr1: Body1-1\e, Body1-2, Hdr2: Body2" . .Mx .It Va datefield diff --git a/nailfuns.h b/nailfuns.h index 1cdad0f3..49269ec4 100644 --- a/nailfuns.h +++ b/nailfuns.h @@ -1867,8 +1867,12 @@ FL int anyof(char const *s1, char const *s2); /* Treat *iolist as a sep separated list of strings; find and return the * next entry, trimming surrounding whitespace, and point *iolist to the next * entry or to NULL if no more entries are contained. If ignore_empty is not - * set empty entries are started over. Return NULL or an entry */ + * set empty entries are started over. + * strescsep will assert that sep is not NULL, and allows escaping of the + * separator character with a backslash. + * Return NULL or an entry */ FL char * n_strsep(char **iolist, char sep, bool_t ignore_empty); +FL char * n_strescsep(char **iolist, char sep, bool_t ignore_empty); /* Copy a string, lowercasing it as we go; *size* is buffer size of *dest*; * *dest* will always be terminated unless *size* is 0 */ diff --git a/nam_a_grp.c b/nam_a_grp.c index 92086fa5..6ff8b8d3 100644 --- a/nam_a_grp.c +++ b/nam_a_grp.c @@ -1823,7 +1823,7 @@ n_customhdr_query(void){ /* XXX Uses salloc()! */ if(vp != NULL){ char *buf = savestr(vp); jch_outer: - while((vp = n_strsep(&buf, ',', TRU1)) != NULL){ + while((vp = n_strescsep(&buf, ',', TRU1)) != NULL){ ui32_t nl, bl; char const *nstart, *cp; diff --git a/strings.c b/strings.c index f1dff729..7ad15fc6 100644 --- a/strings.c +++ b/strings.c @@ -651,6 +651,58 @@ n_strsep(char **iolist, char sep, bool_t ignore_empty) return base; } +FL char * +n_strescsep(char **iolist, char sep, bool_t ignore_empty){ + char *cp, c, *base; + bool_t isesc, anyesc; + NYD2_ENTER; + + assert(sep != '\0'); + + for(base = *iolist; base != NULL; base = *iolist){ + while((c = *base) != '\0' && blankspacechar(c)) + ++base; + + for(isesc = anyesc = FAL0, cp = base;; ++cp){ + if(UNLIKELY((c = *cp) == '\0')){ + *iolist = NULL; + break; + }else if(!isesc){ + if(c == sep){ + *iolist = cp + 1; + break; + } + isesc = (c == '\\'); + }else{ + isesc = FAL0; + anyesc |= (c == sep); + } + } + + while(cp > base && blankspacechar(cp[-1])) + --cp; + *cp = '\0'; + + if(*base != '\0'){ + if(anyesc){ + char *ins; + + for(ins = cp = base;; ++ins) + if((c = *cp) == '\\' && cp[1] == sep){ + *ins = sep; + cp += 2; + }else if((*ins = (++cp, c)) == '\0') + break; + } + break; + } + if(!ignore_empty) + break; + } + NYD2_LEAVE; + return base; +} + FL void i_strcpy(char *dest, char const *src, size_t size) { -- 2.11.4.GIT