From 7fce9e2411b9e63d949ad519f1b6a36744d3df4c Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Thu, 28 Aug 2014 18:27:23 -0700 Subject: [PATCH] Trim trailing newline on cmdsubst when IFS='' When $IFS is empty, command substitution no longer splits on newlines. However we still want to trim off a single trailing newline, as most commands will emit a trailing newline and it makes it harder to work with their output. --- exec.cpp | 45 +++++++++++++++++++++++++++++---------------- tests/read.in | 5 +++++ tests/read.out | 9 +++++++++ 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/exec.cpp b/exec.cpp index dfd04231e..3b5506da6 100644 --- a/exec.cpp +++ b/exec.cpp @@ -1540,7 +1540,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo ASSERT_IS_MAIN_THREAD(); int prev_subshell = is_subshell; const int prev_status = proc_get_last_status(); - char sep=0; + bool split_output=false; //fprintf(stderr, "subcmd %ls\n", cmd.c_str()); @@ -1548,7 +1548,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo if (! ifs.missing_or_empty()) { - sep = '\n'; + split_output=true; } is_subshell=1; @@ -1580,23 +1580,36 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo { const char *begin = io_buffer->out_buffer_ptr(); const char *end = begin + io_buffer->out_buffer_size(); - const char *cursor = begin; - while (cursor < end) + if (split_output) { - // Look for the next separator - const char *stop = (const char *)memchr(cursor, sep, end - cursor); - const bool hit_separator = (stop != NULL); - if (! hit_separator) + const char *cursor = begin; + while (cursor < end) { - // If it's not found, just use the end - stop = end; - } - // Stop now points at the first character we do not want to copy - const wcstring wc = str2wcstring(cursor, stop - cursor); - lst->push_back(wc); + // Look for the next separator + const char *stop = (const char *)memchr(cursor, '\n', end - cursor); + const bool hit_separator = (stop != NULL); + if (! hit_separator) + { + // If it's not found, just use the end + stop = end; + } + // Stop now points at the first character we do not want to copy + const wcstring wc = str2wcstring(cursor, stop - cursor); + lst->push_back(wc); - // If we hit a separator, skip over it; otherwise we're at the end - cursor = stop + (hit_separator ? 1 : 0); + // If we hit a separator, skip over it; otherwise we're at the end + cursor = stop + (hit_separator ? 1 : 0); + } + } + else + { + // we're not splitting output, but we still want to trim off a trailing newline + if (end != begin && end[-1] == '\n') + { + --end; + } + const wcstring wc = str2wcstring(begin, end - begin); + lst->push_back(wc); } } diff --git a/tests/read.in b/tests/read.in index 53f9873b6..f8787c5ce 100644 --- a/tests/read.in +++ b/tests/read.in @@ -7,6 +7,11 @@ set -l IFS \t count (echo one\ntwo) set -l IFS count (echo one\ntwo) +echo [(echo -n one\ntwo)] +count (echo one\ntwo\n) +echo [(echo -n one\ntwo\n)] +count (echo one\ntwo\n\n) +echo [(echo -n one\ntwo\n\n)] set -le IFS function print_vars --no-scope-shadowing diff --git a/tests/read.out b/tests/read.out index 6d90fc0e7..1098045dd 100644 --- a/tests/read.out +++ b/tests/read.out @@ -1,6 +1,15 @@ 2 2 1 +[one +two] +1 +[one +two] +1 +[one +two +] 1 'hello' 1 'there' 1 'hello there'