summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-10-22 11:59:14 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-10-22 11:59:14 +0300
commit2c2e3c50d6a8b5da362983470b67c34ad6d3806a (patch)
treeeea25b83b1cd78672f86c0dc92558fc64ed96b6f
parent4d01c1dea8d700f7b6cac2f2bda95ee8c5cc6cc1 (diff)
downloadmailutils-2c2e3c50d6a8b5da362983470b67c34ad6d3806a.tar.gz
mailutils-2c2e3c50d6a8b5da362983470b67c34ad6d3806a.tar.bz2
Fix wordsplit command expansion and related tests.
* include/mailutils/wordsplit.h (MU_WRDSO_ARGV): Remove. * libmailutils/string/wordsplit.c (expcmd): Always split command line into arguments. This fixes https://savannah.gnu.org/bugs/?54830 * libmailutils/tests/wordsplit.at: Rewrite command expansion tests. * libmailutils/tests/wsp.c: Implement internal commands, instead of calling shell ones. This fixes https://savannah.gnu.org/bugs/?54829. * libmailutils/string/expvar.c: Remove the use of MU_WRDSO_ARGV.
-rw-r--r--include/mailutils/wordsplit.h11
-rw-r--r--libmailutils/string/expvar.c4
-rw-r--r--libmailutils/string/wordsplit.c22
-rw-r--r--libmailutils/tests/wordsplit.at137
-rw-r--r--libmailutils/tests/wsp.c130
5 files changed, 126 insertions, 178 deletions
diff --git a/include/mailutils/wordsplit.h b/include/mailutils/wordsplit.h
index 940f8ba65..d5631ddba 100644
--- a/include/mailutils/wordsplit.h
+++ b/include/mailutils/wordsplit.h
@@ -1,5 +1,5 @@
/* wordsplit - a word splitter
- Copyright (C) 2009-2015 Sergey Poznyakoff
+ Copyright (C) 2009-2018 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -85,9 +85,8 @@ struct mu_wordsplit
void *clos);
/* [Input] (!MU_WRDSF_NOCMD) Returns in the memory
location pointed to by RET the expansion of
- the command CMD (LEN bytes long). If
- MU_WRDSO_ARGV option is set, ARGV contains CMD
- split out to words. Otherwise ARGV is NULL.
+ the command CMD (LEN bytes long). On input,
+ ARGV contains CMD split out to words.
See ws_getvar for a discussion of possible
return values. */
@@ -193,8 +192,10 @@ struct mu_wordsplit
#define MU_WRDSO_FAILGLOB 0x00000002
/* Allow a leading period to be matched by metacharacters. */
#define MU_WRDSO_DOTGLOB 0x00000004
-/* ws_command needs argv parameter */
+#if 0
+/* Unused */
#define MU_WRDSO_ARGV 0x00000008
+#endif
/* Keep backslash in unrecognized escape sequences in words */
#define MU_WRDSO_BSKEEP_WORD 0x00000010
/* Handle octal escapes in words */
diff --git a/libmailutils/string/expvar.c b/libmailutils/string/expvar.c
index 516af52b6..8adef2a24 100644
--- a/libmailutils/string/expvar.c
+++ b/libmailutils/string/expvar.c
@@ -288,11 +288,9 @@ mu_str_expand (char **output, char const *input, mu_assoc_t assoc)
ws.ws_getvar = exp_getvar;
ws.ws_command = exp_runcmd;
ws.ws_closure = assoc;
- ws.ws_options = MU_WRDSO_ARGV;
if (mu_wordsplit (input, &ws,
- MU_WRDSF_NOSPLIT | MU_WRDSF_GETVAR | MU_WRDSF_CLOSURE
- | MU_WRDSF_OPTIONS))
+ MU_WRDSF_NOSPLIT | MU_WRDSF_GETVAR | MU_WRDSF_CLOSURE))
{
if (ws.ws_errno == MU_WRDSE_NOSPACE)
rc = ENOMEM;
diff --git a/libmailutils/string/wordsplit.c b/libmailutils/string/wordsplit.c
index c742554f1..1f9b32a66 100644
--- a/libmailutils/string/wordsplit.c
+++ b/libmailutils/string/wordsplit.c
@@ -1351,6 +1351,7 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t len,
size_t j;
char *value;
struct mu_wordsplit_node *newnode;
+ struct mu_wordsplit ws;
str++;
len--;
@@ -1362,23 +1363,16 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t len,
}
*pend = str + j;
- if (wsp->ws_options & MU_WRDSO_ARGV)
- {
- struct mu_wordsplit ws;
- rc = _wsplt_subsplit (wsp, &ws, str, j,
- MU_WRDSF_WS | MU_WRDSF_QUOTE);
- if (rc)
- {
- _wsplt_seterr_sub (wsp, &ws);
- mu_wordsplit_free (&ws);
- return 1;
- }
- rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
+ rc = _wsplt_subsplit (wsp, &ws, str, j, MU_WRDSF_WS | MU_WRDSF_QUOTE);
+ if (rc)
+ {
+ _wsplt_seterr_sub (wsp, &ws);
mu_wordsplit_free (&ws);
+ return 1;
}
- else
- rc = wsp->ws_command (&value, str, j, NULL, wsp->ws_closure);
+ rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure);
+ mu_wordsplit_free (&ws);
if (rc == MU_WRDSE_NOSPACE)
return _wsplt_nomem (wsp);
diff --git a/libmailutils/tests/wordsplit.at b/libmailutils/tests/wordsplit.at
index d1bb0fd2e..53a69677c 100644
--- a/libmailutils/tests/wordsplit.at
+++ b/libmailutils/tests/wordsplit.at
@@ -619,134 +619,63 @@ TESTWSP([incremental nosplit],[],[incremental nosplit],
[input exhausted
])
-dnl Something that doesn't fit into TESTWSP
-
-AT_SETUP([simple command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-1])
-AT_CHECK([
-mkdir dir
-> dir/file
-
-wsp -nocmd <<'EOT'
-begin $(find dir) end
-EOT
-],
-[0],
+TESTWSP([simple command substitution],[],[-nocmd],
+[begin $(words a b) end],
[NF: 4
0: begin
-1: dir
-2: dir/file
+1: a
+2: b
3: end
])
-AT_CLEANUP
-
-AT_SETUP([quoted command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-2])
-AT_CHECK([
-mkdir dir
-> dir/file
-wsp -nocmd <<'EOT'
-begin "$(find dir)" end
-EOT
-],
-[0],
+TESTWSP([quoted command substitution],[],[-nocmd],
+[begin "$(words a b)" end],
[NF: 3
0: begin
-1: "dir dir/file"
+1: "a b"
2: end
])
-AT_CLEANUP
-
-AT_SETUP([coalesced command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-3])
-AT_CHECK([
-mkdir dir
-> dir/file
-wsp -nocmd <<'EOT'
-begin($(find dir))end
-EOT
-],
-[0],
+TESTWSP([coalesced command substitution],[],[-nocmd],
+[begin($(words a b))end],
[NF: 2
-0: begin(dir
-1: dir/file)end
+0: begin(a
+1: b)end
])
-AT_CLEANUP
-
-AT_SETUP([quoted coalesced command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-cmd wsp-cmd-4])
-AT_CHECK([
-mkdir dir
-> dir/file
-wsp -nocmd <<'EOT'
-"begin($(find dir))end"
-EOT
-],
-[0],
+TESTWSP([quoted coalesced command substitution],[],[-nocmd],
+["begin($(words a b))end"],
[NF: 1
-0: "begin(dir dir/file)end"
+0: "begin(a b)end"
])
-AT_CLEANUP
-
-AT_SETUP([variable and command substitution])
-AT_KEYWORDS([wordsplit wsp wsp-var wsp-var24 wsp-cmd wsp-cmd-5])
-AT_CHECK([
-mkdir dir
-> dir/file
-DIR=dir wsp -nocmd -novar<<'EOT'
-begin $DIR $(find $DIR) end
-EOT
-],
-[0],
+TESTWSP([variable and command substitution],[],[-nocmd -novar],
+[begin $X $(words $X $Y) end],
[NF: 5
0: begin
-1: dir
-2: dir
-3: dir/file
+1: a
+2: a
+3: b
4: end
-])
-AT_CLEANUP
-
-AT_SETUP([variable expansion and command substitution in quotes])
-AT_KEYWORDS([wordsplit wsp wsp-var wsp-var25 wsp-cmd wsp-cmd-6])
-AT_CHECK([
-mkdir dir
-> dir/file
+],[],[X=a Y=b])
-DIR=dir BEGIN=begin wsp -nocmd -novar<<'EOT'
-"${BEGIN}($(find $DIR))end"
-EOT
-],
-[0],
+TESTWSP([variable expansion and command substitution in quotes],[],[-nocmd -novar],
+["${BEGIN}($(words $X $Y))end"],
[NF: 1
-0: "begin(dir dir/file)end"
-])
-AT_CLEANUP
-
-AT_SETUP([nested commands])
-AT_KEYWORDS([wordsplit wsp wsp-cmd])
-AT_CHECK([
-AT_DATA([input],[foo
-bar
-baz
-])
-SUFFIX=put wsp -nocmd -novar <<'EOT'
-$(echo output $(cat in$SUFFIX))
-EOT
-],
-[0],
+0: "begin(a b)end"
+],[],[X=a Y=b BEGIN=begin])
+
+TESTWSP([nested commands],[],[-nocmd -novar],
+[$(words output $(words in$SUFFIX text) end)],
[NF: 4
0: output
-1: foo
-2: bar
-3: baz
-])
-AT_CLEANUP
+1: input
+2: text
+3: end
+],[],[SUFFIX=put])
+dnl Something that doesn't fit into TESTWSP
+
AT_SETUP([pathname expansion])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1])
AT_CHECK([
diff --git a/libmailutils/tests/wsp.c b/libmailutils/tests/wsp.c
index 01a15c749..f0e579992 100644
--- a/libmailutils/tests/wsp.c
+++ b/libmailutils/tests/wsp.c
@@ -183,70 +183,96 @@ wsp_getvar (char **ret, const char *vptr, size_t vlen, void *data)
}
return MU_WRDSE_UNDEF;
}
-
+
static int
-wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
+cmd_quote (char **ret, const char *str, size_t len, char **argv)
{
- FILE *fp;
- char *cmd;
- int c, lastc;
- char *buffer = NULL;
- size_t bufsize = 0;
- size_t buflen = 0;
+ int alen;
+ for (alen = 0; alen < len && !(str[alen] == ' ' || str[alen] == '\t'); alen++)
+ ;
+ for (; alen < len && (str[alen] == ' ' || str[alen] == '\t'); alen++)
+ ;
+ len -= alen;
+ *ret = malloc (len + 1);
+ if (!*ret)
+ return MU_WRDSE_NOSPACE;
+ memcpy (*ret, str + alen, len);
+ (*ret)[len] = 0;
+ return MU_WRDSE_OK;
+}
+
+static int
+cmd_words (char **ret, const char *str, size_t len, char **argv)
+{
+ char *p;
+ int i;
- cmd = malloc (len + 1);
- if (!cmd)
+ p = malloc (len + 1);
+ if (!p)
return MU_WRDSE_NOSPACE;
- memcpy (cmd, str, len);
- cmd[len] = 0;
-
- fp = popen (cmd, "r");
- if (!fp)
+ *ret = p;
+ for (i = 1; argv[i]; i++)
{
- ret = NULL;
- if (mu_asprintf (ret, "can't run %s: %s", cmd, mu_strerror (errno)))
- return MU_WRDSE_NOSPACE;
- else
- return MU_WRDSE_USERERR;
+ size_t s = strlen (argv[i]);
+ if (i > 1)
+ *p++ = ' ';
+ memcpy (p, argv[i], s);
+ p += s;
}
+ *p = 0;
+ return MU_WRDSE_OK;
+}
- while ((c = fgetc (fp)) != EOF)
+static int
+cmd_lines (char **ret, const char *str, size_t len, char **argv)
+{
+ char *p;
+ int i;
+
+ p = malloc (len + 1);
+ if (!p)
+ return MU_WRDSE_NOSPACE;
+ *ret = p;
+ for (i = 1; argv[i]; i++)
{
- lastc = c;
- if (c == '\n')
- c = ' ';
- if (buflen == bufsize)
- {
- char *p;
-
- if (bufsize == 0)
- bufsize = 80;
- else
- bufsize *= 2;
- p = realloc (buffer, bufsize);
- if (!p)
- {
- free (buffer);
- free (cmd);
- return MU_WRDSE_NOSPACE;
- }
- buffer = p;
- }
- buffer[buflen++] = c;
+ size_t s = strlen (argv[i]);
+ if (i > 1)
+ *p++ = '\n';
+ memcpy (p, argv[i], s);
+ p += s;
}
+ *p = 0;
+ return MU_WRDSE_OK;
+}
- if (buffer)
+static struct command
+{
+ char const *name;
+ int (*cmd)(char **ret, const char *str, size_t len, char **argv);
+} comtab[] = {
+ { "quote", cmd_quote },
+ { "words", cmd_words },
+ { "lines", cmd_lines }
+};
+
+static int
+wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
+{
+ int i;
+
+ for (i = 0; ; i++)
{
- if (lastc == '\n')
- --buflen;
- buffer[buflen] = 0;
+ if (i == sizeof (comtab) / sizeof (comtab[0]))
+ break;
+ if (strcmp (comtab[i].name, argv[0]) == 0)
+ return comtab[i].cmd (ret, str, len, argv);
}
-
- pclose (fp);
- free (cmd);
- *ret = buffer;
- return MU_WRDSE_OK;
+ *ret = NULL;
+ if (mu_asprintf (ret, "unknown command: %s", argv[0]))
+ return MU_WRDSE_NOSPACE;
+ else
+ return MU_WRDSE_USERERR;
}
enum env_type
@@ -552,7 +578,7 @@ main (int argc, char **argv)
if (wsflags & MU_WRDSF_INCREMENTAL)
trimnl_option = 1;
-
+
next_call = 0;
while ((ptr = fgets (buf, sizeof (buf), stdin)))
{

Return to:

Send suggestions and report system problems to the System administrator.