Commit 2ec525ac 2ec525acff5a090dcba8a0c7c166bbe745340902 by Sergey Poznyakoff

Improve wordsplit.

* include/mailutils/wordsplit.h (mu_wordsplit) <ws_escape>: New member.
(MU_WRDSF_ESCAPE): New flag.
(mu_wordsplit_general_unquote_copy): New function.
* libmailutils/string/wordsplit.c: Remove empty nodes after whitespace
trimming.  If MU_WRDSF_ESCAPE is set, remove only backslashes appearing
in front of a character in ws_escape.
* libmailutils/tests/wordsplit.at: Test new features.
1 parent b26b2120
......@@ -28,6 +28,7 @@ struct mu_wordsplit
int ws_flags;
const char *ws_delim;
const char *ws_comment;
const char *ws_escape;
void (*ws_alloc_die) (struct mu_wordsplit *wsp);
void (*ws_error) (const char *, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
......@@ -110,6 +111,9 @@ struct mu_wordsplit
stored in the element that follows its name. */
#define MU_WRDSF_ENV_KV 0x4000000
/* ws_escape is set */
#define MU_WRDSF_ESCAPE 0x8000000
#define MU_WRDSF_DEFFLAGS \
(MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | \
MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS | MU_WRDSF_CESCAPES)
......@@ -132,6 +136,8 @@ int mu_wordsplit_c_unquote_char (int c);
int mu_wordsplit_c_quote_char (int c);
size_t mu_wordsplit_c_quoted_length (const char *str, int quote_hex,
int *quote);
void mu_wordsplit_general_unquote_copy (char *dst, const char *src, size_t n,
const char *escapable);
void mu_wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n);
void mu_wordsplit_c_unquote_copy (char *dst, const char *src, size_t n);
void mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex);
......
......@@ -500,7 +500,12 @@ wsnode_quoteremoval (struct mu_wordsplit *wsp)
p->v.word = newstr;
p->flags |= _WSNF_WORD;
}
uqfn (p->v.word, str, slen);
if (wsp->ws_flags & MU_WRDSF_ESCAPE)
mu_wordsplit_general_unquote_copy (p->v.word, str, slen,
wsp->ws_escape);
else
uqfn (p->v.word, str, slen);
}
}
return 0;
......@@ -906,32 +911,39 @@ node_expand_vars (struct mu_wordsplit *wsp, struct mu_wordsplit_node *node)
return 0;
}
static int
mu_wordsplit_varexp (struct mu_wordsplit *wsp)
/* Remove NULL lists */
static void
wsnode_nullelim (struct mu_wordsplit *wsp)
{
struct mu_wordsplit_node *p;
for (p = wsp->ws_head; p;)
{
struct mu_wordsplit_node *next = p->next;
if (!(p->flags & _WSNF_NOEXPAND))
if (node_expand_vars (wsp, p))
return 1;
if (p->flags & _WSNF_NULL)
{
wsnode_remove (wsp, p);
wsnode_free (p);
}
p = next;
}
}
static int
mu_wordsplit_varexp (struct mu_wordsplit *wsp)
{
struct mu_wordsplit_node *p;
/* Remove NULL lists */
for (p = wsp->ws_head; p;)
{
struct mu_wordsplit_node *next = p->next;
if (p->flags & _WSNF_NULL)
{
wsnode_remove (wsp, p);
wsnode_free (p);
}
if (!(p->flags & _WSNF_NOEXPAND))
if (node_expand_vars (wsp, p))
return 1;
p = next;
}
wsnode_nullelim (wsp);
return 0;
}
......@@ -959,7 +971,11 @@ mu_wordsplit_trimws (struct mu_wordsplit *wsp)
for (n = p->v.segm.end; n > p->v.segm.beg && ISWS (wsp->ws_input[n-1]);
n--);
p->v.segm.end = n;
if (p->v.segm.beg == p->v.segm.end)
p->flags |= _WSNF_NULL;
}
wsnode_nullelim (wsp);
}
static int
......@@ -1217,6 +1233,21 @@ mu_wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote)
}
void
mu_wordsplit_general_unquote_copy (char *dst, const char *src, size_t n,
const char *escapable)
{
int i;
for (i = 0; i < n;)
{
if (src[i] == '\\' && i < n && strchr (escapable, src[i+1]))
i++;
*dst++ = src[i++];
}
*dst = 0;
}
void
mu_wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n)
{
int i;
......
......@@ -313,6 +313,15 @@ TESTWSP([C escapes off],[],[-cescapes],
3: newnline
])
TESTWSP([ws elimination],[],[delim ' ()' ws return_delims],
[( list items )],
[NF: 4
0: (
1: list
2: items
3: )
])
TESTWSP([empty quotes],[],[delim : ws return_delims],
[t=""],
[NF: 1
......@@ -338,4 +347,12 @@ TESTWSP([suppress ws trimming within quotes],[],
4: "formatfield=In message %{text}, "
])
TESTWSP([unescape],[],[-default novar nocmd quote escape '\"'],
[\Seen "quote \"" "bs \\"],
[NF: 3
0: \\Seen
1: "quote \""
2: "bs \\"
])
m4_popdef([TESTWSP])
......