Commit 151eb4b9 151eb4b9e00a56a1e4c85e8120403385012eb95a by Sergey Poznyakoff

Fix command expansion in wordsplit

* libmailutils/string/wordsplit.c: Change ordering of expansions so
that command expansion occurs first.  This fixes nested expansions
and command expansions occurring after variable expansions.
* libmailutils/tests/wordsplit.at: Add more tests.
1 parent a923b221
......@@ -1332,7 +1332,6 @@ expcmd (struct mu_wordsplit *wsp, const char *str, size_t len,
struct mu_wordsplit ws;
rc = _wsplt_subsplit (wsp, &ws, str, j,
MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
MU_WRDSF_WS | MU_WRDSF_QUOTE);
if (rc)
{
......@@ -2065,29 +2064,41 @@ mu_wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex)
}
}
/* This structure describes a single expansion phase */
struct exptab
{
char *descr;
int flag;
int opt;
int (*expansion) (struct mu_wordsplit *wsp);
char *descr; /* Textual description (for debugging) */
int flag; /* MU_WRDSF_ bit that controls this phase */
int opt; /* Entry-specific options (see EXPOPT_ flags below */
int (*expansion) (struct mu_wordsplit *wsp); /* expansion function */
};
/* The following options control expansions: */
/* Normally the exptab entry is run if its flag bit is set in struct
wordsplit. The EXPOPT_NEG option negates this test so that expansion
is performed if its associated flag bit is not set in struct wordsplit. */
#define EXPOPT_NEG 0x01
/* Coalesce the input list before running the expansion. */
#define EXPOPT_COALESCE 0x02
static struct exptab exptab[] = {
{ N_("WS trimming"), MU_WRDSF_WS, 0, mu_wordsplit_trimws },
{ N_("tilde expansion"), MU_WRDSF_PATHEXPAND, 0, mu_wordsplit_tildexpand },
{ N_("WS trimming"), MU_WRDSF_WS, 0,
mu_wordsplit_trimws },
{ N_("command substitution"), MU_WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE,
mu_wordsplit_cmdexp },
{ N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE,
NULL },
{ N_("tilde expansion"), MU_WRDSF_PATHEXPAND, 0,
mu_wordsplit_tildexpand },
{ N_("variable expansion"), MU_WRDSF_NOVAR, EXPOPT_NEG,
mu_wordsplit_varexp },
{ N_("quote removal"), 0, EXPOPT_NEG,
wsnode_quoteremoval },
{ N_("command substitution"), MU_WRDSF_NOCMD, EXPOPT_NEG|EXPOPT_COALESCE,
mu_wordsplit_cmdexp },
{ N_("coalesce list"), 0, EXPOPT_NEG|EXPOPT_COALESCE,
NULL },
{ N_("path expansion"), MU_WRDSF_PATHEXPAND, 0, mu_wordsplit_pathexpand },
{ N_("path expansion"), MU_WRDSF_PATHEXPAND, 0,
mu_wordsplit_pathexpand },
{ NULL }
};
......
......@@ -421,4 +421,207 @@ NF: 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],
[NF: 4
0: begin
1: dir
2: dir/file
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],
[NF: 3
0: begin
1: "dir dir/file"
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],
[NF: 2
0: begin(dir
1: dir/file)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],
[NF: 1
0: "begin(dir dir/file)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],
[NF: 5
0: begin
1: dir
2: dir
3: dir/file
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
DIR=dir BEGIN=begin wsp -nocmd -novar<<'EOT'
"${BEGIN}($(find $DIR))end"
EOT
],
[0],
[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],
[NF: 4
0: output
1: foo
2: bar
3: baz
])
AT_CLEANUP
AT_SETUP([pathname expansion])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-1])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.c
> dir/3.b
wsp pathexpand<<'EOT'
begin dir/*.c end
EOT
],
[0],
[NF: 4
0: begin
1: dir/1.c
2: dir/2.c
3: end
])
AT_CLEANUP
AT_SETUP([pathname expansion: no match])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-2])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b
wsp pathexpand<<'EOT'
begin dir/*.d end
EOT
],
[0],
[NF: 3
0: begin
1: dir/*.d
2: end
])
AT_CLEANUP
AT_SETUP([pathname expansion: nullglob])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-3])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b
wsp pathexpand nullglob<<'EOT'
begin dir/*.d end
EOT
],
[0],
[NF: 2
0: begin
1: end
])
AT_CLEANUP
AT_SETUP([pathname expansion: failglob])
AT_KEYWORDS([wordsplit wsp wsp-path wsp-path-4])
AT_CHECK([
mkdir dir
> dir/1.c
> dir/2.b
wsp pathexpand failglob<<'EOT'
begin dir/*.d end
EOT
],
[0],
[],
[no files match pattern dir/*.d
])
AT_CLEANUP
m4_popdef([TESTWSP])
......