diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-10-22 11:59:14 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-10-22 11:59:14 +0300 |
commit | 2c2e3c50d6a8b5da362983470b67c34ad6d3806a (patch) | |
tree | eea25b83b1cd78672f86c0dc92558fc64ed96b6f | |
parent | 4d01c1dea8d700f7b6cac2f2bda95ee8c5cc6cc1 (diff) | |
download | mailutils-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.h | 11 | ||||
-rw-r--r-- | libmailutils/string/expvar.c | 4 | ||||
-rw-r--r-- | libmailutils/string/wordsplit.c | 22 | ||||
-rw-r--r-- | libmailutils/tests/wordsplit.at | 137 | ||||
-rw-r--r-- | libmailutils/tests/wsp.c | 130 |
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))) { |