diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2016-01-10 21:26:11 -0500 |
---|---|---|
committer | Justin M. Keyes <justinkz@gmail.com> | 2016-01-10 21:26:11 -0500 |
commit | 223aafb1a75c9ece9a2283a887b7539a3b771550 (patch) | |
tree | 039e4a402f1281eea651b197701d4c700ae7ea95 /src/nvim/strings.c | |
parent | 095320a67da7b96824cd7495357b69e2a4fdb047 (diff) | |
parent | 3b7c4093e24fd413696e3f0aba9a7a1a470a8b4f (diff) | |
download | rneovim-223aafb1a75c9ece9a2283a887b7539a3b771550.tar.gz rneovim-223aafb1a75c9ece9a2283a887b7539a3b771550.tar.bz2 rneovim-223aafb1a75c9ece9a2283a887b7539a3b771550.zip |
Merge pull request #3980 from ZyX-I/shell-unquote
shell: Unquote &shell* options before using them
Diffstat (limited to 'src/nvim/strings.c')
-rw-r--r-- | src/nvim/strings.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 00dcf3cf46..fe91141375 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -119,6 +119,54 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, return escaped_string; } +/// Save a copy of an unquoted string +/// +/// Turns string like `a\bc"def\"ghi\\\n"jkl` into `a\bcdef"ghi\\njkl`, for use +/// in shell_build_argv: the only purpose of backslash is making next character +/// be treated literally inside the double quotes, if this character is +/// backslash or quote. +/// +/// @param[in] string String to copy. +/// @param[in] length Length of the string to copy. +/// +/// @return [allocated] Copy of the string. +char *vim_strnsave_unquoted(const char *const string, const size_t length) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_RET +{ +#define ESCAPE_COND(p, inquote, string_end) \ + (*p == '\\' && inquote && p + 1 < string_end && (p[1] == '\\' || p[1] == '"')) + size_t ret_length = 0; + bool inquote = false; + const char *const string_end = string + length; + for (const char *p = string; p < string_end; p++) { + if (*p == '"') { + inquote = !inquote; + } else if (ESCAPE_COND(p, inquote, string_end)) { + ret_length++; + p++; + } else { + ret_length++; + } + } + + char *const ret = xmallocz(ret_length); + char *rp = ret; + inquote = false; + for (const char *p = string; p < string_end; p++) { + if (*p == '"') { + inquote = !inquote; + } else if (ESCAPE_COND(p, inquote, string_end)) { + *rp++ = *(++p); + } else { + *rp++ = *p; + } + } +#undef ESCAPE_COND + + return ret; +} + /* * Escape "string" for use as a shell argument with system(). * This uses single quotes, except when we know we need to use double quotes |