From 6e4ef4c272a23ffde227689bc4e65a0523f18b4d Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 15 Nov 2018 09:58:01 +0200 Subject: Port mailutils commit 2c2e3c50d6 * include/wordsplit.h (WRDSO_ARGV): Remove. * src/wordsplit.c (expcmd): Always split command line into arguments. This fixes https://savannah.gnu.org/bugs/?54830 * tests/wsp.c: Implement internal commands, instead of calling shell ones. This fixes https://savannah.gnu.org/bugs/?54829. * tests/wordsplit.at: Rewrite command expansion tests. --- include/wordsplit.h | 8 +-- src/wordsplit.c | 20 +++----- tests/wordsplit.at | 138 +++++++++++++--------------------------------------- tests/wsp.c | 131 +++++++++++++++++++++++++++++-------------------- 4 files changed, 122 insertions(+), 175 deletions(-) diff --git a/include/wordsplit.h b/include/wordsplit.h index 7229df3..1a047f7 100644 --- a/include/wordsplit.h +++ b/include/wordsplit.h @@ -88,9 +88,8 @@ struct wordsplit void *clos); /* [Input] (!WRDSF_NOCMD) Returns in the memory location pointed to by RET the expansion of - the command CMD (LEN bytes long). If 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. */ @@ -196,9 +195,10 @@ struct wordsplit #define WRDSO_FAILGLOB 0x00000002 /* Allow a leading period to be matched by metacharacters. */ #define WRDSO_DOTGLOB 0x00000004 -/* ws_command needs argv parameter */ +#if 0 /* Unused value */ #define WRDSO_ARGV 0x00000008 /* Keep backslash in unrecognized escape sequences in words */ +#endif #define WRDSO_BSKEEP_WORD 0x00000010 /* Handle octal escapes in words */ #define WRDSO_OESC_WORD 0x00000020 diff --git a/src/wordsplit.c b/src/wordsplit.c index b4baeb3..bad59b1 100644 --- a/src/wordsplit.c +++ b/src/wordsplit.c @@ -1527,6 +1527,7 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len, size_t j; char *value; struct wordsplit_node *newnode; + struct wordsplit ws; str++; len--; @@ -1538,22 +1539,15 @@ expcmd (struct wordsplit *wsp, const char *str, size_t len, } *pend = str + j; - if (wsp->ws_options & WRDSO_ARGV) + rc = _wsplt_subsplit (wsp, &ws, str, j, WRDSF_WS | WRDSF_QUOTE, 1); + if (rc) { - struct wordsplit ws; - - rc = _wsplt_subsplit (wsp, &ws, str, j, WRDSF_WS | WRDSF_QUOTE, 1); - if (rc) - { - _wsplt_seterr_sub (wsp, &ws); - wordsplit_free (&ws); - return 1; - } - rc = wsp->ws_command (&value, str, j, ws.ws_wordv, wsp->ws_closure); + _wsplt_seterr_sub (wsp, &ws); 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); + wordsplit_free (&ws); if (rc == WRDSE_NOSPACE) return _wsplt_nomem (wsp); diff --git a/tests/wordsplit.at b/tests/wordsplit.at index 75dde85..631d939 100644 --- a/tests/wordsplit.at +++ b/tests/wordsplit.at @@ -711,142 +711,70 @@ TOTAL: 1 ], [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 TOTAL: 4 ]) -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 TOTAL: 3 ]) -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 TOTAL: 2 ]) -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" TOTAL: 1 ]) -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 TOTAL: 5 -]) -AT_CLEANUP +],[],[X=a Y=b]) -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 - -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" +0: "begin(a b)end" TOTAL: 1 -]) -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], +],[],[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 +1: input +2: text +3: end TOTAL: 4 -]) -AT_CLEANUP +],[],[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/tests/wsp.c b/tests/wsp.c index a96fb7f..cca3a36 100644 --- a/tests/wsp.c +++ b/tests/wsp.c @@ -201,72 +201,97 @@ wsp_getvar (char **ret, const char *vptr, size_t vlen, void *data) } return 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 WRDSE_NOSPACE; + memcpy (*ret, str + alen, len); + (*ret)[len] = 0; + return 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 WRDSE_NOSPACE; - memcpy (cmd, str, len); - cmd[len] = 0; - - fp = popen(cmd, "r"); - if (!fp) + *ret = p; + for (i = 1; argv[i]; i++) { - size_t size = 0; - ret = NULL; - if (grecs_asprintf (ret, &size, "can't run %s: %s", - cmd, strerror (errno))) - return WRDSE_NOSPACE; - else - return WRDSE_USERERR; + size_t s = strlen (argv[i]); + if (i > 1) + *p++ = ' '; + memcpy (p, argv[i], s); + p += s; } + *p = 0; + return 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 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 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 WRDSE_OK; +} + +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 } +}; - if (buffer) +static int +wsp_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure) +{ + int i; + size_t s = 0; + + 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 WRDSE_OK; + *ret = NULL; + if (grecs_asprintf (ret, &s, "unknown command: %s", argv[0])) + return WRDSE_NOSPACE; + else + return WRDSE_USERERR; } enum env_type -- cgit v1.2.1