neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

shell.c (39835B)


      1 #include <assert.h>
      2 #include <stdbool.h>
      3 #include <stdint.h>
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <uv.h>
      7 
      8 #include "auto/config.h"
      9 #include "klib/kvec.h"
     10 #include "nvim/ascii_defs.h"
     11 #include "nvim/buffer.h"
     12 #include "nvim/charset.h"
     13 #include "nvim/errors.h"
     14 #include "nvim/eval/typval_defs.h"
     15 #include "nvim/eval/vars.h"
     16 #include "nvim/event/defs.h"
     17 #include "nvim/event/libuv_proc.h"
     18 #include "nvim/event/loop.h"
     19 #include "nvim/event/multiqueue.h"
     20 #include "nvim/event/proc.h"
     21 #include "nvim/event/rstream.h"
     22 #include "nvim/event/stream.h"
     23 #include "nvim/event/wstream.h"
     24 #include "nvim/ex_cmds.h"
     25 #include "nvim/fileio.h"
     26 #include "nvim/gettext_defs.h"
     27 #include "nvim/globals.h"
     28 #include "nvim/macros_defs.h"
     29 #include "nvim/main.h"
     30 #include "nvim/mbyte.h"
     31 #include "nvim/memline.h"
     32 #include "nvim/memory.h"
     33 #include "nvim/message.h"
     34 #include "nvim/option_vars.h"
     35 #include "nvim/os/fs.h"
     36 #include "nvim/os/os.h"
     37 #include "nvim/os/os_defs.h"
     38 #include "nvim/os/shell.h"
     39 #include "nvim/os/signal.h"
     40 #include "nvim/os/time.h"
     41 #include "nvim/path.h"
     42 #include "nvim/pos_defs.h"
     43 #include "nvim/profile.h"
     44 #include "nvim/state_defs.h"
     45 #include "nvim/strings.h"
     46 #include "nvim/tag.h"
     47 #include "nvim/types_defs.h"
     48 #include "nvim/ui.h"
     49 #include "nvim/vim_defs.h"
     50 
     51 #define NS_1_SECOND         1000000000U     // 1 second, in nanoseconds
     52 #define OUT_DATA_THRESHOLD  1024 * 10U      // 10KB, "a few screenfuls" of data.
     53 
     54 #define SHELL_SPECIAL "\t \"&'$;<>()\\|"
     55 
     56 #include "os/shell.c.generated.h"
     57 
     58 static void save_patterns(int num_pat, char **pat, int *num_file, char ***file)
     59 {
     60  *file = xmalloc((size_t)num_pat * sizeof(char *));
     61  for (int i = 0; i < num_pat; i++) {
     62    char *s = xstrdup(pat[i]);
     63    // Be compatible with expand_filename(): halve the number of
     64    // backslashes.
     65    backslash_halve(s);
     66    (*file)[i] = s;
     67  }
     68  *num_file = num_pat;
     69 }
     70 
     71 static bool have_wildcard(int num, char **file)
     72 {
     73  for (int i = 0; i < num; i++) {
     74    if (path_has_wildcard(file[i])) {
     75      return true;
     76    }
     77  }
     78  return false;
     79 }
     80 
     81 static bool have_dollars(int num, char **file)
     82 {
     83  for (int i = 0; i < num; i++) {
     84    if (vim_strchr(file[i], '$') != NULL) {
     85      return true;
     86    }
     87  }
     88  return false;
     89 }
     90 
     91 /// Performs wildcard pattern matching using the shell.
     92 ///
     93 /// @param      num_pat  is the number of input patterns.
     94 /// @param      pat      is an array of pointers to input patterns.
     95 /// @param[out] num_file is pointer to number of matched file names.
     96 ///                      Set to the number of pointers in *file.
     97 /// @param[out] file     is pointer to array of pointers to matched file names.
     98 ///                      Memory pointed to by the initial value of *file will
     99 ///                      not be freed.
    100 ///                      Set to NULL if FAIL is returned. Otherwise points to
    101 ///                      allocated memory.
    102 /// @param      flags    is a combination of EW_* flags used in
    103 ///                      expand_wildcards().
    104 ///                      If matching fails but EW_NOTFOUND is set in flags or
    105 ///                      there are no wildcards, the patterns from pat are
    106 ///                      copied into *file.
    107 ///
    108 /// @returns             OK for success or FAIL for error.
    109 int os_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, int flags)
    110  FUNC_ATTR_NONNULL_ARG(3)
    111  FUNC_ATTR_NONNULL_ARG(4)
    112 {
    113  int i;
    114  size_t len;
    115  char *p;
    116  char *extra_shell_arg = NULL;
    117  int shellopts = kShellOptExpand | kShellOptSilent;
    118  int j;
    119  char *tempname;
    120 #define STYLE_ECHO      0       // use "echo", the default
    121 #define STYLE_GLOB      1       // use "glob", for csh
    122 #define STYLE_VIMGLOB   2       // use "vimglob", for Posix sh
    123 #define STYLE_PRINT     3       // use "print -N", for zsh
    124 #define STYLE_BT        4       // `cmd` expansion, execute the pattern directly
    125 #define STYLE_GLOBSTAR  5       // use extended shell glob for bash (this uses extended
    126                                // globbing functionality with globstar, needs bash > 4)
    127  int shell_style = STYLE_ECHO;
    128  int check_spaces;
    129  static bool did_find_nul = false;
    130  bool ampersand = false;
    131  // vimglob() function to define for Posix shell
    132  static char *sh_vimglob_func =
    133    "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
    134  // vimglob() function with globstar setting enabled, only for bash >= 4.X
    135  static char *sh_globstar_opt =
    136    "[[ ${BASH_VERSINFO[0]} -ge 4 ]] && shopt -s globstar; ";
    137 
    138  bool is_fish_shell =
    139 #if defined(UNIX)
    140    strncmp(invocation_path_tail(p_sh, NULL), "fish", 4) == 0;
    141 #else
    142    false;
    143 #endif
    144 
    145  *num_file = 0;        // default: no files found
    146  *file = NULL;
    147 
    148  // If there are no wildcards, just copy the names to allocated memory.
    149  // Saves a lot of time, because we don't have to start a new shell.
    150  if (!have_wildcard(num_pat, pat)) {
    151    save_patterns(num_pat, pat, num_file, file);
    152    return OK;
    153  }
    154 
    155  // Don't allow any shell command in the sandbox.
    156  if (sandbox != 0 && check_secure()) {
    157    return FAIL;
    158  }
    159 
    160  // Don't allow the use of backticks in secure.
    161  if (secure) {
    162    for (i = 0; i < num_pat; i++) {
    163      if (vim_strchr(pat[i], '`') != NULL
    164          && (check_secure())) {
    165        return FAIL;
    166      }
    167    }
    168  }
    169 
    170  // get a name for the temp file
    171  if ((tempname = vim_tempname()) == NULL) {
    172    emsg(_(e_notmp));
    173    return FAIL;
    174  }
    175 
    176  // Let the shell expand the patterns and write the result into the temp
    177  // file.
    178  // STYLE_BT:         NL separated
    179  //       If expanding `cmd` execute it directly.
    180  // STYLE_GLOB:       NUL separated
    181  //       If we use *csh, "glob" will work better than "echo".
    182  // STYLE_PRINT:      NL or NUL separated
    183  //       If we use *zsh, "print -N" will work better than "glob".
    184  // STYLE_VIMGLOB:    NL separated
    185  //       If we use *sh*, we define "vimglob()".
    186  // STYLE_GLOBSTAR:   NL separated
    187  //       If we use *bash*, we define "vimglob() and enable globstar option".
    188  // STYLE_ECHO:       space separated.
    189  //       A shell we don't know, stay safe and use "echo".
    190  if (num_pat == 1 && *pat[0] == '`'
    191      && (len = strlen(pat[0])) > 2
    192      && *(pat[0] + len - 1) == '`') {
    193    shell_style = STYLE_BT;
    194  } else if ((len = strlen(p_sh)) >= 3) {
    195    if (strcmp(p_sh + len - 3, "csh") == 0) {
    196      shell_style = STYLE_GLOB;
    197    } else if (strcmp(p_sh + len - 3, "zsh") == 0) {
    198      shell_style = STYLE_PRINT;
    199    }
    200  }
    201  if (shell_style == STYLE_ECHO) {
    202    if (strstr(path_tail(p_sh), "bash") != NULL) {
    203      shell_style = STYLE_GLOBSTAR;
    204    } else if (strstr(path_tail(p_sh), "sh") != NULL) {
    205      shell_style = STYLE_VIMGLOB;
    206    }
    207  }
    208 
    209  // Compute the length of the command.  We need 2 extra bytes: for the
    210  // optional '&' and for the NUL.
    211  // Worst case: "unset nonomatch; print -N >" plus two is 29
    212  len = strlen(tempname) + 29;
    213  if (shell_style == STYLE_VIMGLOB) {
    214    len += strlen(sh_vimglob_func);
    215  } else if (shell_style == STYLE_GLOBSTAR) {
    216    len += strlen(sh_vimglob_func) + strlen(sh_globstar_opt);
    217  }
    218 
    219  for (i = 0; i < num_pat; i++) {
    220    // Count the length of the patterns in the same way as they are put in
    221    // "command" below.
    222    len++;                              // add space
    223    for (j = 0; pat[i][j] != NUL; j++) {
    224      if (vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) {
    225        len++;                  // may add a backslash
    226      }
    227      len++;
    228    }
    229  }
    230 
    231  if (is_fish_shell) {
    232    len += sizeof("egin;" " end") - 1;
    233  }
    234 
    235  char *command = xmalloc(len);
    236 
    237  // Build the shell command:
    238  // - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
    239  //    recognizes this).
    240  // - Add the shell command to print the expanded names.
    241  // - Add the temp file name.
    242  // - Add the file name patterns.
    243  if (shell_style == STYLE_BT) {
    244    // change `command; command& ` to (command; command )
    245    if (is_fish_shell) {
    246      STRCPY(command, "begin; ");
    247    } else {
    248      STRCPY(command, "(");
    249    }
    250    strcat(command, pat[0] + 1);                // exclude first backtick
    251    p = command + strlen(command) - 1;
    252    if (is_fish_shell) {
    253      *p-- = ';';
    254      strcat(command, " end");
    255    } else {
    256      *p-- = ')';                                 // remove last backtick
    257    }
    258    while (p > command && ascii_iswhite(*p)) {
    259      p--;
    260    }
    261    if (*p == '&') {                            // remove trailing '&'
    262      ampersand = true;
    263      *p = ' ';
    264    }
    265    strcat(command, ">");
    266  } else {
    267    STRCPY(command, "");
    268    if (shell_style == STYLE_GLOB) {
    269      // Assume the nonomatch option is valid only for csh like shells,
    270      // otherwise, this may set the positional parameters for the shell,
    271      // e.g. "$*".
    272      if (flags & EW_NOTFOUND) {
    273        strcat(command, "set nonomatch; ");
    274      } else {
    275        strcat(command, "unset nonomatch; ");
    276      }
    277    }
    278    if (shell_style == STYLE_GLOB) {
    279      strcat(command, "glob >");
    280    } else if (shell_style == STYLE_PRINT) {
    281      strcat(command, "print -N >");
    282    } else if (shell_style == STYLE_VIMGLOB) {
    283      strcat(command, sh_vimglob_func);
    284    } else if (shell_style == STYLE_GLOBSTAR) {
    285      strcat(command, sh_globstar_opt);
    286      strcat(command, sh_vimglob_func);
    287    } else {
    288      strcat(command, "echo >");
    289    }
    290  }
    291 
    292  strcat(command, tempname);
    293 
    294  if (shell_style != STYLE_BT) {
    295    for (i = 0; i < num_pat; i++) {
    296      // Put a backslash before special
    297      // characters, except inside ``.
    298      bool intick = false;
    299 
    300      p = command + strlen(command);
    301      *p++ = ' ';
    302      for (j = 0; pat[i][j] != NUL; j++) {
    303        if (pat[i][j] == '`') {
    304          intick = !intick;
    305        } else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL) {
    306          // Remove a backslash, take char literally.  But keep
    307          // backslash inside backticks, before a special character
    308          // and before a backtick.
    309          if (intick
    310              || vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j + 1]) != NULL
    311              || pat[i][j + 1] == '`') {
    312            *p++ = '\\';
    313          }
    314          j++;
    315        } else if (!intick
    316                   && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
    317                   && vim_strchr(SHELL_SPECIAL, (uint8_t)pat[i][j]) != NULL) {
    318          // Put a backslash before a special character, but not
    319          // when inside ``. And not for $var when EW_KEEPDOLLAR is
    320          // set.
    321          *p++ = '\\';
    322        }
    323 
    324        // Copy one character.
    325        *p++ = pat[i][j];
    326      }
    327      *p = NUL;
    328    }
    329  }
    330 
    331  if (flags & EW_SILENT) {
    332    shellopts |= kShellOptHideMess;
    333  }
    334 
    335  if (ampersand) {
    336    strcat(command, "&");               // put the '&' after the redirection
    337  }
    338 
    339  // Using zsh -G: If a pattern has no matches, it is just deleted from
    340  // the argument list, otherwise zsh gives an error message and doesn't
    341  // expand any other pattern.
    342  if (shell_style == STYLE_PRINT) {
    343    extra_shell_arg = "-G";       // Use zsh NULL_GLOB option
    344 
    345    // If we use -f then shell variables set in .cshrc won't get expanded.
    346    // vi can do it, so we will too, but it is only necessary if there is a "$"
    347    // in one of the patterns, otherwise we can still use the fast option.
    348  } else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat)) {
    349    extra_shell_arg = "-f";           // Use csh fast option
    350  }
    351 
    352  // execute the shell command
    353  i = call_shell(command, shellopts, extra_shell_arg);
    354 
    355  // When running in the background, give it some time to create the temp
    356  // file, but don't wait for it to finish.
    357  if (ampersand) {
    358    os_delay(10, true);
    359  }
    360 
    361  xfree(command);
    362 
    363  if (i) {                         // os_call_shell() failed
    364    os_remove(tempname);
    365    xfree(tempname);
    366    // With interactive completion, the error message is not printed.
    367    if (!(flags & EW_SILENT)) {
    368      msg_putchar('\n');                // clear bottom line quickly
    369      cmdline_row = Rows - 1;           // continue on last line
    370      msg(_(e_wildexpand), 0);
    371      msg_start();                    // don't overwrite this message
    372    }
    373 
    374    // If a `cmd` expansion failed, don't list `cmd` as a match, even when
    375    // EW_NOTFOUND is given
    376    if (shell_style == STYLE_BT) {
    377      return FAIL;
    378    }
    379    goto notfound;
    380  }
    381 
    382  // read the names from the file into memory
    383  FILE *fd = fopen(tempname, READBIN);
    384  if (fd == NULL) {
    385    // Something went wrong, perhaps a file name with a special char.
    386    if (!(flags & EW_SILENT)) {
    387      msg(_(e_wildexpand), 0);
    388      msg_start();                      // don't overwrite this message
    389    }
    390    xfree(tempname);
    391    goto notfound;
    392  }
    393  int fseek_res = fseek(fd, 0, SEEK_END);
    394  if (fseek_res < 0) {
    395    xfree(tempname);
    396    fclose(fd);
    397    return FAIL;
    398  }
    399  int64_t templen = ftell(fd);        // get size of temp file
    400  if (templen < 0) {
    401    xfree(tempname);
    402    fclose(fd);
    403    return FAIL;
    404  }
    405 #if 8 > SIZEOF_SIZE_T
    406  assert(templen <= SIZE_MAX);  // NOLINT(runtime/int)
    407 #endif
    408  len = (size_t)templen;
    409  fseek(fd, 0, SEEK_SET);
    410  char *buffer = xmalloc(len + 1);
    411  // fread() doesn't terminate buffer with NUL;
    412  // appropriate termination (not always NUL) is done below.
    413  size_t readlen = fread(buffer, 1, len, fd);
    414  fclose(fd);
    415  os_remove(tempname);
    416  if (readlen != len) {
    417    // unexpected read error
    418    semsg(_(e_cant_read_file_str), tempname);
    419    xfree(tempname);
    420    xfree(buffer);
    421    return FAIL;
    422  }
    423  xfree(tempname);
    424 
    425  // file names are separated with Space
    426  if (shell_style == STYLE_ECHO) {
    427    buffer[len] = '\n';                 // make sure the buffer ends in NL
    428    p = buffer;
    429    for (i = 0; *p != '\n'; i++) {      // count number of entries
    430      while (*p != ' ' && *p != '\n') {
    431        p++;
    432      }
    433      p = skipwhite(p);                 // skip to next entry
    434    }
    435    // file names are separated with NL
    436  } else if (shell_style == STYLE_BT
    437             || shell_style == STYLE_VIMGLOB
    438             || shell_style == STYLE_GLOBSTAR) {
    439    buffer[len] = NUL;                  // make sure the buffer ends in NUL
    440    p = buffer;
    441    for (i = 0; *p != NUL; i++) {       // count number of entries
    442      while (*p != '\n' && *p != NUL) {
    443        p++;
    444      }
    445      if (*p != NUL) {
    446        p++;
    447      }
    448      p = skipwhite(p);                 // skip leading white space
    449    }
    450    // file names are separated with NUL
    451  } else {
    452    // Some versions of zsh use spaces instead of NULs to separate
    453    // results.  Only do this when there is no NUL before the end of the
    454    // buffer, otherwise we would never be able to use file names with
    455    // embedded spaces when zsh does use NULs.
    456    // When we found a NUL once, we know zsh is OK, set did_find_nul and
    457    // don't check for spaces again.
    458    check_spaces = false;
    459    if (shell_style == STYLE_PRINT && !did_find_nul) {
    460      // If there is a NUL, set did_find_nul, else set check_spaces
    461      buffer[len] = NUL;
    462      if (len && (int)strlen(buffer) < (int)len) {
    463        did_find_nul = true;
    464      } else {
    465        check_spaces = true;
    466      }
    467    }
    468 
    469    // Make sure the buffer ends with a NUL.  For STYLE_PRINT there
    470    // already is one, for STYLE_GLOB it needs to be added.
    471    if (len && buffer[len - 1] == NUL) {
    472      len--;
    473    } else {
    474      buffer[len] = NUL;
    475    }
    476    for (p = buffer; p < buffer + len; p++) {
    477      if (*p == NUL || (*p == ' ' && check_spaces)) {       // count entry
    478        i++;
    479        *p = NUL;
    480      }
    481    }
    482    if (len) {
    483      i++;                              // count last entry
    484    }
    485  }
    486  assert(buffer[len] == NUL || buffer[len] == '\n');
    487 
    488  if (i == 0) {
    489    // Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
    490    // /bin/sh will happily expand it to nothing rather than returning an
    491    // error; and hey, it's good to check anyway -- webb.
    492    xfree(buffer);
    493    goto notfound;
    494  }
    495  *num_file = i;
    496  *file = xmalloc(sizeof(char *) * (size_t)i);
    497 
    498  // Isolate the individual file names.
    499  p = buffer;
    500  for (i = 0; i < *num_file; i++) {
    501    (*file)[i] = p;
    502    // Space or NL separates
    503    if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
    504        || shell_style == STYLE_VIMGLOB || shell_style == STYLE_GLOBSTAR) {
    505      while (!(shell_style == STYLE_ECHO && *p == ' ')
    506             && *p != '\n' && *p != NUL) {
    507        p++;
    508      }
    509      if (p == buffer + len) {                  // last entry
    510        *p = NUL;
    511      } else {
    512        *p++ = NUL;
    513        p = skipwhite(p);                       // skip to next entry
    514      }
    515    } else {          // NUL separates
    516      while (*p && p < buffer + len) {          // skip entry
    517        p++;
    518      }
    519      p++;                                      // skip NUL
    520    }
    521  }
    522 
    523  // Move the file names to allocated memory.
    524  for (j = 0, i = 0; i < *num_file; i++) {
    525    // Require the files to exist. Helps when using /bin/sh
    526    if (!(flags & EW_NOTFOUND) && !os_path_exists((*file)[i])) {
    527      continue;
    528    }
    529 
    530    // check if this entry should be included
    531    bool dir = (os_isdir((*file)[i]));
    532    if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) {
    533      continue;
    534    }
    535 
    536    // Skip files that are not executable if we check for that.
    537    if (!dir && (flags & EW_EXEC)
    538        && !os_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD))) {
    539      continue;
    540    }
    541 
    542    p = xmalloc(strlen((*file)[i]) + 1 + dir);
    543    STRCPY(p, (*file)[i]);
    544    if (dir) {
    545      add_pathsep(p);             // add '/' to a directory name
    546    }
    547    (*file)[j++] = p;
    548  }
    549  xfree(buffer);
    550  *num_file = j;
    551 
    552  if (*num_file == 0) {     // rejected all entries
    553    XFREE_CLEAR(*file);
    554    goto notfound;
    555  }
    556 
    557  return OK;
    558 
    559 notfound:
    560  if (flags & EW_NOTFOUND) {
    561    save_patterns(num_pat, pat, num_file, file);
    562    return OK;
    563  }
    564  return FAIL;
    565 }
    566 
    567 /// Builds the argument vector for running the user-configured 'shell' (p_sh)
    568 /// with an optional command prefixed by 'shellcmdflag' (p_shcf). E.g.:
    569 ///
    570 ///   ["shell", "-extra_args", "-shellcmdflag", "command with spaces"]
    571 ///
    572 /// @param cmd Command string, or NULL to run an interactive shell.
    573 /// @param extra_args Extra arguments to the shell, or NULL.
    574 /// @return Newly allocated argument vector. Must be freed with shell_free_argv.
    575 char **shell_build_argv(const char *cmd, const char *extra_args)
    576  FUNC_ATTR_NONNULL_RET
    577 {
    578  size_t argc = tokenize(p_sh, NULL) + (cmd ? tokenize(p_shcf, NULL) : 0);
    579  char **rv = xmalloc((argc + 4) * sizeof(*rv));
    580 
    581  // Split 'shell'
    582  size_t i = tokenize(p_sh, rv);
    583 
    584  if (extra_args) {
    585    rv[i++] = xstrdup(extra_args);        // Push a copy of `extra_args`
    586  }
    587 
    588  if (cmd) {
    589    i += tokenize(p_shcf, rv + i);        // Split 'shellcmdflag'
    590    rv[i++] = shell_xescape_xquote(cmd);  // Copy (and escape) `cmd`.
    591  }
    592 
    593  rv[i] = NULL;
    594 
    595  assert(rv[0]);
    596 
    597  return rv;
    598 }
    599 
    600 /// Releases the memory allocated by `shell_build_argv`.
    601 ///
    602 /// @param argv The argument vector.
    603 void shell_free_argv(char **argv)
    604 {
    605  char **p = argv;
    606  if (p == NULL) {
    607    // Nothing was allocated, return
    608    return;
    609  }
    610  while (*p != NULL) {
    611    // Free each argument
    612    xfree(*p);
    613    p++;
    614  }
    615  xfree(argv);
    616 }
    617 
    618 /// Joins shell arguments from `argv` into a new string.
    619 /// If the result is too long it is truncated with ellipsis ("...").
    620 ///
    621 /// @returns[allocated] `argv` joined to a string.
    622 char *shell_argv_to_str(char **const argv)
    623  FUNC_ATTR_NONNULL_ALL
    624 {
    625  size_t n = 0;
    626  char **p = argv;
    627  char *rv = xcalloc(256, sizeof(*rv));
    628  const size_t maxsize = (256 * sizeof(*rv));
    629  if (*p == NULL) {
    630    return rv;
    631  }
    632  while (*p != NULL) {
    633    xstrlcat(rv, "'", maxsize);
    634    xstrlcat(rv, *p, maxsize);
    635    n = xstrlcat(rv,  "' ", maxsize);
    636    if (n >= maxsize) {
    637      break;
    638    }
    639    p++;
    640  }
    641  if (n < maxsize) {
    642    rv[n - 1] = NUL;
    643  } else {
    644    // Command too long, show ellipsis: "/bin/bash 'foo' 'bar'..."
    645    rv[maxsize - 4] = '.';
    646    rv[maxsize - 3] = '.';
    647    rv[maxsize - 2] = '.';
    648    rv[maxsize - 1] = NUL;
    649  }
    650  return rv;
    651 }
    652 
    653 /// Calls the user-configured 'shell' (p_sh) for running a command or wildcard
    654 /// expansion.
    655 ///
    656 /// @param cmd The command to execute, or NULL to run an interactive shell.
    657 /// @param opts Options that control how the shell will work.
    658 /// @param extra_args Extra arguments to the shell, or NULL.
    659 ///
    660 /// @return shell command exit code
    661 int os_call_shell(char *cmd, int opts, char *extra_args)
    662 {
    663  StringBuilder input = KV_INITIAL_VALUE;
    664  char *output = NULL;
    665  char **output_ptr = NULL;
    666  int current_state = State;
    667  bool forward_output = true;
    668 
    669  // While the child is running, ignore terminating signals
    670  signal_reject_deadly();
    671 
    672  if (opts & (kShellOptHideMess | kShellOptExpand)) {
    673    forward_output = false;
    674  } else {
    675    State = MODE_EXTERNCMD;
    676 
    677    if (opts & kShellOptWrite) {
    678      read_input(&input);
    679    }
    680 
    681    if (opts & kShellOptRead) {
    682      output_ptr = &output;
    683      forward_output = false;
    684    } else if (opts & kShellOptDoOut) {
    685      // Caller has already redirected output
    686      forward_output = false;
    687    }
    688  }
    689 
    690  size_t nread;
    691  int exitcode = do_os_system(shell_build_argv(cmd, extra_args),
    692                              input.items, input.size, output_ptr, &nread,
    693                              emsg_silent, forward_output);
    694  kv_destroy(input);
    695 
    696  if (output) {
    697    write_output(output, nread, true);
    698    xfree(output);
    699  }
    700 
    701  if (!emsg_silent && exitcode != 0 && !(opts & kShellOptSilent)) {
    702    msg_ext_set_kind("shell_ret");
    703    msg_puts(_("\nshell returned "));
    704    msg_outnum(exitcode);
    705    msg_putchar('\n');
    706  }
    707 
    708  State = current_state;
    709  signal_accept_deadly();
    710 
    711  return exitcode;
    712 }
    713 
    714 /// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
    715 /// Invalidates cached tags.
    716 ///
    717 /// @param opts  a combination of ShellOpts flags
    718 ///
    719 /// @return shell command exit code
    720 int call_shell(char *cmd, int opts, char *extra_shell_arg)
    721 {
    722  int retval;
    723  proftime_T wait_time;
    724 
    725  if (p_verbose > 3) {
    726    verbose_enter();
    727    smsg(0, _("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd);
    728    msg_putchar('\n');
    729    verbose_leave();
    730  }
    731 
    732  if (do_profiling == PROF_YES) {
    733    prof_child_enter(&wait_time);
    734  }
    735 
    736  if (*p_sh == NUL) {
    737    emsg(_(e_shellempty));
    738    retval = -1;
    739  } else {
    740    // The external command may update a tags file, clear cached tags.
    741    tag_freematch();
    742 
    743    retval = os_call_shell(cmd, opts, extra_shell_arg);
    744  }
    745 
    746  set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T)retval);
    747  if (do_profiling == PROF_YES) {
    748    prof_child_exit(&wait_time);
    749  }
    750 
    751  return retval;
    752 }
    753 
    754 /// Get the stdout of an external command.
    755 /// If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
    756 /// NULL store the length there.
    757 ///
    758 /// @param  cmd      command to execute
    759 /// @param  infile   optional input file name
    760 /// @param  flags    can be kShellOptSilent or 0
    761 /// @param  ret_len  length of the stdout
    762 ///
    763 /// @return an allocated string, or NULL for error.
    764 char *get_cmd_output(char *cmd, char *infile, int flags, size_t *ret_len)
    765 {
    766  char *buffer = NULL;
    767 
    768  if (check_secure()) {
    769    return NULL;
    770  }
    771 
    772  // get a name for the temp file
    773  char *tempname = vim_tempname();
    774  if (tempname == NULL) {
    775    emsg(_(e_notmp));
    776    return NULL;
    777  }
    778 
    779  // Add the redirection stuff
    780  char *command = make_filter_cmd(cmd, infile, tempname, false);
    781 
    782  // Call the shell to execute the command (errors are ignored).
    783  // Don't check timestamps here.
    784  no_check_timestamps++;
    785  call_shell(command, kShellOptDoOut | kShellOptExpand | flags, NULL);
    786  no_check_timestamps--;
    787 
    788  xfree(command);
    789 
    790  // read the names from the file into memory
    791  FILE *fd = os_fopen(tempname, READBIN);
    792 
    793  // Not being able to seek means we can't read the file.
    794  long len_l;
    795  if (fd == NULL
    796      || fseek(fd, 0L, SEEK_END) == -1
    797      || (len_l = ftell(fd)) == -1         // get size of temp file
    798      || fseek(fd, 0L, SEEK_SET) == -1) {  // back to the start
    799    semsg(_(e_cannot_read_from_str_2), tempname);
    800    if (fd != NULL) {
    801      fclose(fd);
    802    }
    803    goto done;
    804  }
    805 
    806  size_t len = (size_t)len_l;
    807  buffer = xmalloc(len + 1);
    808  size_t i = fread(buffer, 1, len, fd);
    809  fclose(fd);
    810  os_remove(tempname);
    811  if (i != len) {
    812    semsg(_(e_cant_read_file_str), tempname);
    813    XFREE_CLEAR(buffer);
    814  } else if (ret_len == NULL) {
    815    // Change NUL into SOH, otherwise the string is truncated.
    816    for (i = 0; i < len; i++) {
    817      if (buffer[i] == NUL) {
    818        buffer[i] = 1;
    819      }
    820    }
    821 
    822    buffer[len] = NUL;          // make sure the buffer is terminated
    823  } else {
    824    *ret_len = len;
    825  }
    826 
    827 done:
    828  xfree(tempname);
    829  return buffer;
    830 }
    831 /// os_system - synchronously execute a command in the shell
    832 ///
    833 /// example:
    834 ///   char *output = NULL;
    835 ///   size_t nread = 0;
    836 ///   char *argv[] = {"ls", "-la", NULL};
    837 ///   int exitcode = os_system(argv, NULL, 0, &output, &nread);
    838 ///
    839 /// @param argv The commandline arguments to be passed to the shell. `argv`
    840 ///             will be consumed.
    841 /// @param input The input to the shell (NULL for no input), passed to the
    842 ///              stdin of the resulting process.
    843 /// @param len The length of the input buffer (not used if `input` == NULL)
    844 /// @param[out] output Pointer to a location where the output will be
    845 ///                    allocated and stored. Will point to NULL if the shell
    846 ///                    command did not output anything. If NULL is passed,
    847 ///                    the shell output will be ignored.
    848 /// @param[out] nread the number of bytes in the returned buffer (if the
    849 ///             returned buffer is not NULL)
    850 /// @return the return code of the process, -1 if the process couldn't be
    851 ///         started properly
    852 int os_system(char **argv, const char *input, size_t len, char **output,
    853              size_t *nread) FUNC_ATTR_NONNULL_ARG(1)
    854 {
    855  return do_os_system(argv, input, len, output, nread, true, false);
    856 }
    857 
    858 static int do_os_system(char **argv, const char *input, size_t len, char **output, size_t *nread,
    859                        bool silent, bool forward_output)
    860 {
    861  int exitcode = -1;
    862 
    863 #ifdef MSWIN
    864  // do not execute anything from the current directory by setting the
    865  // environment variable $NoDefaultCurrentDirectoryInExePath
    866  char *oldval = os_getenv("NoDefaultCurrentDirectoryInExePath");
    867  os_setenv("NoDefaultCurrentDirectoryInExePath", "1", true);
    868 #endif
    869 
    870  out_data_decide_throttle(0);  // Initialize throttle decider.
    871  out_data_ring(NULL, 0);       // Initialize output ring-buffer.
    872  bool has_input = (input != NULL && len > 0);
    873 
    874  // the output buffer
    875  StringBuilder buf = KV_INITIAL_VALUE;
    876  stream_read_cb data_cb = system_data_cb;
    877  if (nread) {
    878    *nread = 0;
    879  }
    880 
    881  if (forward_output) {
    882    data_cb = out_data_cb;
    883  } else if (!output) {
    884    data_cb = NULL;
    885  }
    886 
    887  // Copy the program name in case we need to report an error.
    888  char prog[MAXPATHL];
    889  xstrlcpy(prog, argv[0], MAXPATHL);
    890 
    891  LibuvProc uvproc = libuv_proc_init(&main_loop, &buf);
    892  Proc *proc = &uvproc.proc;
    893  MultiQueue *events = multiqueue_new_child(main_loop.events);
    894  proc->events = events;
    895  proc->argv = argv;
    896  int status = proc_spawn(proc, has_input, true, true);
    897  if (status) {
    898    loop_poll_events(&main_loop, 0);
    899    // Failed, probably 'shell' is not executable.
    900    if (!silent) {
    901      msg_puts(_("\nshell failed to start: "));
    902      msg_outtrans(os_strerror(status), 0, false);
    903      msg_puts(": ");
    904      msg_outtrans(prog, 0, false);
    905      msg_putchar('\n');
    906    }
    907    goto end;
    908  }
    909 
    910  // Note: unlike process events, stream events are not queued, as we want to
    911  // deal with stream events as fast a possible.  It prevents closing the
    912  // streams while there's still data in the OS buffer (due to the process
    913  // exiting before all data is read).
    914  if (has_input) {
    915    wstream_init(&proc->in, 0);
    916  }
    917  rstream_init(&proc->out);
    918  rstream_start(&proc->out, data_cb, &buf);
    919  rstream_init(&proc->err);
    920  rstream_start(&proc->err, data_cb, &buf);
    921 
    922  // write the input, if any
    923  if (has_input) {
    924    WBuffer *input_buffer = wstream_new_buffer((char *)input, len, 1, NULL);
    925 
    926    if (wstream_write(&proc->in, input_buffer) != 0) {
    927      // couldn't write, stop the process and tell the user about it
    928      proc_stop(proc);
    929      goto end;
    930    }
    931    // close the input stream after everything is written
    932    wstream_set_write_cb(&proc->in, shell_write_cb, NULL);
    933  }
    934 
    935  // Invoke busy_start here so LOOP_PROCESS_EVENTS_UNTIL will not change the
    936  // busy state.
    937  ui_busy_start();
    938  ui_flush();
    939  if (forward_output) {
    940    msg_sb_eol();
    941    msg_start();
    942    msg_no_more = true;
    943    lines_left = -1;
    944  }
    945  exitcode = proc_wait(proc, -1, NULL);
    946  if (!got_int && out_data_decide_throttle(0)) {
    947    // Last chunk of output was skipped; display it now.
    948    out_data_ring(NULL, SIZE_MAX);
    949  }
    950  if (forward_output) {
    951    // caller should decide if wait_return() is invoked
    952    no_wait_return++;
    953    msg_end();
    954    no_wait_return--;
    955    msg_no_more = false;
    956  }
    957 
    958  ui_busy_stop();
    959 
    960  // prepare the out parameters if requested
    961  if (output) {
    962    assert(nread);
    963    if (buf.size == 0) {
    964      // no data received from the process, return NULL
    965      *output = NULL;
    966      *nread = 0;
    967      kv_destroy(buf);
    968    } else {
    969      *nread = buf.size;
    970      // NUL-terminate to make the output directly usable as a C string
    971      kv_push(buf, NUL);
    972      *output = buf.items;
    973    }
    974  }
    975 
    976  assert(multiqueue_empty(events));
    977 end:
    978  multiqueue_free(events);
    979 
    980 #ifdef MSWIN
    981  // Restore original value of NoDefaultCurrentDirectoryInExePath
    982  restore_env_var("NoDefaultCurrentDirectoryInExePath", oldval, true);
    983 #endif
    984 
    985  return exitcode;
    986 }
    987 
    988 static size_t system_data_cb(RStream *stream, const char *buf, size_t count, void *data, bool eof)
    989 {
    990  StringBuilder *dbuf = data;
    991  kv_concat_len(*dbuf, buf, count);
    992  return count;
    993 }
    994 
    995 /// Tracks output received for the current executing shell command, and displays
    996 /// a pulsing "..." when output should be skipped. Tracking depends on the
    997 /// synchronous/blocking nature of ":!".
    998 ///
    999 /// Purpose:
   1000 ///   1. CTRL-C is more responsive. #1234 #5396
   1001 ///   2. Improves performance of :! (UI, esp. TUI, is the bottleneck).
   1002 ///   3. Avoids OOM during long-running, spammy :!.
   1003 ///
   1004 /// Vim does not need this hack because:
   1005 ///   1. :! in terminal-Vim runs in cooked mode, so CTRL-C is caught by the
   1006 ///      terminal and raises SIGINT out-of-band.
   1007 ///   2. :! in terminal-Vim uses a tty (Nvim uses pipes), so commands
   1008 ///      (e.g. `git grep`) may page themselves.
   1009 ///
   1010 /// @param size Length of data, used with internal state to decide whether
   1011 ///             output should be skipped. size=0 resets the internal state and
   1012 ///             returns the previous decision.
   1013 ///
   1014 /// @returns true if output should be skipped and pulse was displayed.
   1015 ///          Returns the previous decision if size=0.
   1016 static bool out_data_decide_throttle(size_t size)
   1017 {
   1018  static uint64_t started = 0;  // Start time of the current throttle.
   1019  static size_t received = 0;  // Bytes observed since last throttle.
   1020  static size_t visit = 0;  // "Pulse" count of the current throttle.
   1021  static char pulse_msg[] = { ' ', ' ', ' ', NUL };
   1022 
   1023  if (!size) {
   1024    bool previous_decision = (visit > 0);
   1025    started = received = visit = 0;
   1026    return previous_decision;
   1027  }
   1028 
   1029  received += size;
   1030  if (received < OUT_DATA_THRESHOLD
   1031      // Display at least the first chunk of output even if it is big.
   1032      || (!started && received < size + 1000)) {
   1033    return false;
   1034  } else if (!visit) {
   1035    started = os_hrtime();
   1036  } else {
   1037    uint64_t since = os_hrtime() - started;
   1038    if (since < (visit * (NS_1_SECOND / 10))) {
   1039      return true;
   1040    }
   1041    if (since > (3 * NS_1_SECOND)) {
   1042      received = visit = 0;
   1043      return false;
   1044    }
   1045  }
   1046 
   1047  visit++;
   1048  // Pulse "..." at the bottom of the screen.
   1049  size_t tick = visit % 4;
   1050  pulse_msg[0] = (tick > 0) ? '.' : ' ';
   1051  pulse_msg[1] = (tick > 1) ? '.' : ' ';
   1052  pulse_msg[2] = (tick > 2) ? '.' : ' ';
   1053  if (visit == 1) {
   1054    msg_puts("...\n");
   1055  }
   1056  msg_putchar('\r');  // put cursor at start of line
   1057  msg_puts(pulse_msg);
   1058  msg_putchar('\r');
   1059  ui_flush();
   1060  return true;
   1061 }
   1062 
   1063 /// Saves output in a quasi-ringbuffer. Used to ensure the last ~page of
   1064 /// output for a shell-command is always displayed.
   1065 ///
   1066 /// Init mode: Resets the internal state.
   1067 ///   output = NULL
   1068 ///   size   = 0
   1069 /// Print mode: Displays the current saved data.
   1070 ///   output = NULL
   1071 ///   size   = SIZE_MAX
   1072 ///
   1073 /// @param  output  Data to save, or NULL to invoke a special mode.
   1074 /// @param  size    Length of `output`.
   1075 static void out_data_ring(const char *output, size_t size)
   1076 {
   1077 #define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
   1078  static char last_skipped[MAX_CHUNK_SIZE];  // Saved output.
   1079  static size_t last_skipped_len = 0;
   1080 
   1081  assert(output != NULL || (size == 0 || size == SIZE_MAX));
   1082 
   1083  if (output == NULL && size == 0) {          // Init mode
   1084    last_skipped_len = 0;
   1085    return;
   1086  }
   1087 
   1088  if (output == NULL && size == SIZE_MAX) {   // Print mode
   1089    out_data_append_to_screen(last_skipped, &last_skipped_len, STDOUT_FILENO, true);
   1090    return;
   1091  }
   1092 
   1093  // This is basically a ring-buffer...
   1094  if (size >= MAX_CHUNK_SIZE) {               // Save mode
   1095    size_t start = size - MAX_CHUNK_SIZE;
   1096    memcpy(last_skipped, output + start, MAX_CHUNK_SIZE);
   1097    last_skipped_len = MAX_CHUNK_SIZE;
   1098  } else if (size > 0) {
   1099    // Length of the old data that can be kept.
   1100    size_t keep_len = MIN(last_skipped_len, MAX_CHUNK_SIZE - size);
   1101    size_t keep_start = last_skipped_len - keep_len;
   1102    // Shift the kept part of the old data to the start.
   1103    if (keep_start) {
   1104      memmove(last_skipped, last_skipped + keep_start, keep_len);
   1105    }
   1106    // Copy the entire new data to the remaining space.
   1107    memcpy(last_skipped + keep_len, output, size);
   1108    last_skipped_len = keep_len + size;
   1109  }
   1110 }
   1111 
   1112 /// Continue to append data to last screen line.
   1113 ///
   1114 /// @param output       Data to append to screen lines.
   1115 /// @param count        Size of data.
   1116 /// @param eof          If true, there will be no more data output.
   1117 static void out_data_append_to_screen(const char *output, size_t *count, int fd, bool eof)
   1118  FUNC_ATTR_NONNULL_ALL
   1119 {
   1120  const char *p = output;
   1121  const char *end = output + *count;
   1122  msg_ext_set_kind(fd == STDERR_FILENO ? "shell_err" : "shell_out");
   1123  while (p < end) {
   1124    if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
   1125      msg_putchar_hl((uint8_t)(*p), fd == STDERR_FILENO ? HLF_SE : HLF_SO);
   1126      p++;
   1127    } else {
   1128      // Note: this is not 100% precise:
   1129      // 1. we don't check if received continuation bytes are already invalid
   1130      //    and we thus do some buffering that could be avoided
   1131      // 2. we don't compose chars over buffer boundaries, even if we see an
   1132      //    incomplete UTF-8 sequence that could be composing with the last
   1133      //    complete sequence.
   1134      // This will be corrected when we switch to vterm based implementation
   1135      int i = *p ? utfc_ptr2len_len(p, (int)(end - p)) : 1;
   1136      if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end - p)) {
   1137        *count = (size_t)(p - output);
   1138        goto end;
   1139      }
   1140 
   1141      msg_outtrans_len(p, i, fd == STDERR_FILENO ? HLF_SE : HLF_SO, false);
   1142      p += i;
   1143    }
   1144  }
   1145 
   1146 end:
   1147  ui_flush();
   1148 }
   1149 
   1150 static size_t out_data_cb(RStream *stream, const char *ptr, size_t count, void *data, bool eof)
   1151 {
   1152  if (count > 0 && out_data_decide_throttle(count)) {  // Skip output above a threshold.
   1153    // Save the skipped output. If it is the final chunk, we display it later.
   1154    out_data_ring(ptr, count);
   1155  } else if (count > 0) {
   1156    out_data_append_to_screen(ptr, &count, stream->s.fd, eof);
   1157  }
   1158 
   1159  return count;
   1160 }
   1161 
   1162 /// Parses a command string into a sequence of words, taking quotes into
   1163 /// consideration.
   1164 ///
   1165 /// @param str The command string to be parsed
   1166 /// @param argv The vector that will be filled with copies of the parsed
   1167 ///        words. It can be NULL if the caller only needs to count words.
   1168 /// @return The number of words parsed.
   1169 static size_t tokenize(const char *const str, char **const argv)
   1170  FUNC_ATTR_NONNULL_ARG(1)
   1171 {
   1172  size_t argc = 0;
   1173  const char *p = str;
   1174 
   1175  while (*p != NUL) {
   1176    const size_t len = word_length(p);
   1177 
   1178    if (argv != NULL) {
   1179      // Fill the slot
   1180      argv[argc] = vim_strnsave_unquoted(p, len);
   1181    }
   1182 
   1183    argc++;
   1184    p = skipwhite((p + len));
   1185  }
   1186 
   1187  return argc;
   1188 }
   1189 
   1190 /// Calculates the length of a shell word.
   1191 ///
   1192 /// @param str A pointer to the first character of the word
   1193 /// @return The offset from `str` at which the word ends.
   1194 static size_t word_length(const char *str)
   1195 {
   1196  const char *p = str;
   1197  bool inquote = false;
   1198  size_t length = 0;
   1199 
   1200  // Move `p` to the end of shell word by advancing the pointer while it's
   1201  // inside a quote or it's a non-whitespace character
   1202  while (*p && (inquote || (*p != ' ' && *p != TAB))) {
   1203    if (*p == '"') {
   1204      // Found a quote character, switch the `inquote` flag
   1205      inquote = !inquote;
   1206    } else if (*p == '\\' && inquote) {
   1207      p++;
   1208      length++;
   1209    }
   1210 
   1211    p++;
   1212    length++;
   1213  }
   1214 
   1215  return length;
   1216 }
   1217 
   1218 /// To remain compatible with the old implementation (which forked a process
   1219 /// for writing) the entire text is copied to a temporary buffer before the
   1220 /// event loop starts. If we don't (by writing in chunks returned by `ml_get`)
   1221 /// the buffer being modified might get modified by reading from the process
   1222 /// before we finish writing.
   1223 static void read_input(StringBuilder *buf)
   1224 {
   1225  read_buffer_into(curbuf, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum, buf);
   1226 }
   1227 
   1228 static size_t write_output(char *output, size_t remaining, bool eof)
   1229 {
   1230  if (!output) {
   1231    return 0;
   1232  }
   1233 
   1234  char *start = output;
   1235  size_t off = 0;
   1236  while (off < remaining) {
   1237    // CRLF
   1238    if (output[off] == CAR && output[off + 1] == NL) {
   1239      output[off] = NUL;
   1240      ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
   1241      size_t skip = off + 2;
   1242      output += skip;
   1243      remaining -= skip;
   1244      off = 0;
   1245      continue;
   1246    } else if (output[off] == CAR || output[off] == NL) {
   1247      // Insert the line
   1248      output[off] = NUL;
   1249      ml_append(curwin->w_cursor.lnum++, output, (int)off + 1, false);
   1250      size_t skip = off + 1;
   1251      output += skip;
   1252      remaining -= skip;
   1253      off = 0;
   1254      continue;
   1255    }
   1256 
   1257    if (output[off] == NUL) {
   1258      // Translate NUL to NL
   1259      output[off] = NL;
   1260    }
   1261    off++;
   1262  }
   1263 
   1264  if (eof) {
   1265    if (remaining) {
   1266      // append unfinished line
   1267      ml_append(curwin->w_cursor.lnum++, output, 0, false);
   1268      // remember that the line ending was missing
   1269      curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
   1270      output += remaining;
   1271    } else {
   1272      curbuf->b_no_eol_lnum = 0;
   1273    }
   1274  }
   1275 
   1276  ui_flush();
   1277 
   1278  return (size_t)(output - start);
   1279 }
   1280 
   1281 static void shell_write_cb(Stream *stream, void *data, int status)
   1282 {
   1283  if (status) {
   1284    // Can happen if system() tries to send input to a shell command that was
   1285    // backgrounded (:call system("cat - &", "foo")). #3529 #5241
   1286    msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"),
   1287                       uv_err_name(status));
   1288  }
   1289  stream_may_close(stream);
   1290 }
   1291 
   1292 /// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command.
   1293 ///
   1294 /// @param cmd Command string
   1295 /// @return    Escaped/quoted command string (allocated).
   1296 static char *shell_xescape_xquote(const char *cmd)
   1297  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
   1298 {
   1299  if (*p_sxq == NUL) {
   1300    return xstrdup(cmd);
   1301  }
   1302 
   1303  const char *ecmd = cmd;
   1304  if (*p_sxe != NUL && strcmp(p_sxq, "(") == 0) {
   1305    ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', false);
   1306  }
   1307  size_t ncmd_size = strlen(ecmd) + strlen(p_sxq) * 2 + 1;
   1308  char *ncmd = xmalloc(ncmd_size);
   1309 
   1310  // When 'shellxquote' is ( append ).
   1311  // When 'shellxquote' is "( append )".
   1312  if (strcmp(p_sxq, "(") == 0) {
   1313    vim_snprintf(ncmd, ncmd_size, "(%s)", ecmd);
   1314  } else if (strcmp(p_sxq, "\"(") == 0) {
   1315    vim_snprintf(ncmd, ncmd_size, "\"(%s)\"", ecmd);
   1316  } else {
   1317    vim_snprintf(ncmd, ncmd_size, "%s%s%s", p_sxq, ecmd, p_sxq);
   1318  }
   1319 
   1320  if (ecmd != cmd) {
   1321    xfree((void *)ecmd);
   1322  }
   1323 
   1324  return ncmd;
   1325 }