#include #include #include "os/shell.h" #include "types.h" #include "vim.h" #include "ascii.h" #include "misc2.h" #include "option_defs.h" #include "charset.h" static int tokenize(char_u *str, char **argv); static int word_length(char_u *command); // Returns the argument vector for running a shell, with an optional command // and extra shell option. char ** shell_build_argv(char_u *cmd, char_u *extra_shell_opt) { int i; char **rv; int argc = tokenize(p_sh, NULL) + tokenize(p_shcf, NULL); rv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *))); if (rv == NULL) { // out of memory return NULL; } // Split 'shell' i = tokenize(p_sh, rv); if (extra_shell_opt != NULL) { // Push a copy of `extra_shell_opt` rv[i++] = strdup((char *)extra_shell_opt); } if (cmd != NULL) { // Split 'shellcmdflag' i += tokenize(p_shcf, rv + i); rv[i++] = strdup((char *)cmd); } rv[i] = NULL; return rv; } void shell_free_argv(char **argv) { char **p = argv; if (p == NULL) { // Nothing was allocated, return return; } while (*p != NULL) { // Free each argument free(*p); p++; } free(argv); } // Walks through a string and returns the number of shell tokens it contains. // If a non-null `argv` parameter is passed, it will be filled with copies // of the tokens. static int tokenize(char_u *str, char **argv) { int argc = 0, len; char_u *p = str; while (*p != NUL) { len = word_length(p); if (argv != NULL) { // Fill the slot argv[argc] = malloc(len + 1); memcpy(argv[argc], p, len); argv[argc][len] = NUL; } argc++; p += len; p = skipwhite(p); } return argc; } // Returns the length of the shell token in `str` static int word_length(char_u *str) { char_u *p = str; bool inquote = false; int length = 0; // Move `p` to the end of shell word by advancing the pointer while it's // inside a quote or it's a non-whitespace character while (*p && (inquote || (*p != ' ' && *p != TAB))) { if (*p == '"') { // Found a quote character, switch the `inquote` flag inquote = !inquote; } p++; length++; } return length; }