mirror of
https://github.com/neovim/neovim.git
synced 2025-09-13 06:48:17 +00:00
Refactor/cleanup argument parsing functions
This commit is contained in:
149
src/os/shell.c
149
src/os/shell.c
@@ -9,108 +9,105 @@
|
|||||||
#include "option_defs.h"
|
#include "option_defs.h"
|
||||||
#include "charset.h"
|
#include "charset.h"
|
||||||
|
|
||||||
|
static int tokenize(char_u *str, char **argv);
|
||||||
|
static int word_length(char_u *command);
|
||||||
|
|
||||||
void shell_skip_word(char_u **cmd)
|
// 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)
|
||||||
{
|
{
|
||||||
char_u *p = *cmd;
|
int i;
|
||||||
bool inquote = false;
|
char **rv;
|
||||||
|
int argc = tokenize(p_sh, NULL) + tokenize(p_shcf, NULL);
|
||||||
|
|
||||||
// Move `p` to the end of shell word by advancing the pointer it while it's
|
rv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
|
||||||
// inside a quote or it's a non-whitespace character
|
|
||||||
while (*p && (inquote || (*p != ' ' && *p != TAB))) {
|
if (rv == NULL) {
|
||||||
if (*p == '"')
|
// out of memory
|
||||||
// Found a quote character, switch the `inquote` flag
|
return NULL;
|
||||||
inquote = !inquote;
|
|
||||||
++p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*cmd = p;
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
int shell_count_argc(char_u **ptr)
|
if (cmd != NULL) {
|
||||||
{
|
// Split 'shellcmdflag'
|
||||||
int rv = 0;
|
i += tokenize(p_shcf, rv + i);
|
||||||
char_u *p = *ptr;
|
rv[i++] = strdup((char *)cmd);
|
||||||
|
|
||||||
while (true) {
|
|
||||||
rv++;
|
|
||||||
shell_skip_word(&p);
|
|
||||||
if (*p == NUL)
|
|
||||||
break;
|
|
||||||
// Move to the next word
|
|
||||||
p = skipwhite(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account for multiple args in p_shcf('shellcmdflag' option)
|
rv[i] = NULL;
|
||||||
p = p_shcf;
|
|
||||||
while (true) {
|
|
||||||
// Same as above, but doesn't need to take quotes into consideration
|
|
||||||
p = skiptowhite(p);
|
|
||||||
if (*p == NUL)
|
|
||||||
break;
|
|
||||||
rv++;
|
|
||||||
p = skipwhite(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
*ptr = p;
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ** shell_build_argv(int argc, char_u *cmd,
|
void shell_free_argv(char **argv)
|
||||||
char_u *extra_shell_arg, char_u **ptr, char_u **p_shcf_copy_ptr)
|
|
||||||
{
|
{
|
||||||
char **argv;
|
char **p = argv;
|
||||||
char_u *p_shcf_copy = *p_shcf_copy_ptr;
|
|
||||||
char_u *p = *ptr;
|
|
||||||
// Allocate argv memory
|
|
||||||
argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
|
|
||||||
if (argv == NULL) // out of memory
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Build argv[]
|
if (p == NULL) {
|
||||||
argc = 0;
|
// Nothing was allocated, return
|
||||||
while (true) {
|
return;
|
||||||
argv[argc] = (char *)p;
|
|
||||||
++argc;
|
|
||||||
shell_skip_word(&p);
|
|
||||||
if (*p == NUL)
|
|
||||||
break;
|
|
||||||
// Terminate the word
|
|
||||||
*p++ = NUL;
|
|
||||||
p = skipwhite(p);
|
|
||||||
}
|
}
|
||||||
if (cmd != NULL) {
|
|
||||||
char_u *s;
|
|
||||||
|
|
||||||
if (extra_shell_arg != NULL)
|
while (*p != NULL) {
|
||||||
argv[argc++] = (char *)extra_shell_arg;
|
// Free each argument
|
||||||
|
free(*p);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
// Break 'shellcmdflag' into white separated parts. This doesn't
|
|
||||||
// handle quoted strings, they are very unlikely to appear.
|
|
||||||
p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
|
|
||||||
if (p_shcf_copy == NULL) {
|
|
||||||
// out of memory
|
|
||||||
free(argv);
|
free(argv);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s = p_shcf_copy;
|
// Walks through a string and returns the number of shell tokens it contains.
|
||||||
p = p_shcf;
|
// 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) {
|
while (*p != NUL) {
|
||||||
argv[argc++] = (char *)s;
|
len = word_length(p);
|
||||||
while (*p && *p != ' ' && *p != TAB)
|
|
||||||
*s++ = *p++;
|
if (argv != NULL) {
|
||||||
*s++ = NUL;
|
// Fill the slot
|
||||||
|
argv[argc] = malloc(len + 1);
|
||||||
|
memcpy(argv[argc], p, len);
|
||||||
|
argv[argc][len] = NUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
argc++;
|
||||||
|
p += len;
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
argv[argc++] = (char *)cmd;
|
return argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
argv[argc] = NULL;
|
// Returns the length of the shell token in `str`
|
||||||
*ptr = p;
|
static int word_length(char_u *str)
|
||||||
*p_shcf_copy_ptr = p_shcf_copy;
|
{
|
||||||
|
char_u *p = str;
|
||||||
|
bool inquote = false;
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
return argv;
|
// 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;
|
||||||
}
|
}
|
||||||
|
@@ -5,10 +5,8 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void shell_skip_word(char_u **ptr);
|
char ** shell_build_argv(char_u *cmd, char_u *extra_shell_arg);
|
||||||
int shell_count_argc(char_u **ptr);
|
void shell_free_argv(char **argv);
|
||||||
char ** shell_build_argv(int argc, char_u *cmd,
|
|
||||||
char_u *extra_shell_arg, char_u **ptr, char_u **p_shcf_copy_ptr);
|
|
||||||
|
|
||||||
#endif // NEOVIM_OS_SHELL_H
|
#endif // NEOVIM_OS_SHELL_H
|
||||||
|
|
||||||
|
@@ -1688,7 +1688,6 @@ int mch_call_shell(char_u *cmd, int options, char_u *extra_shell_arg)
|
|||||||
# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
|
# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
|
||||||
127, some shells use that already */
|
127, some shells use that already */
|
||||||
|
|
||||||
char_u *newcmd = NULL;
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
pid_t wpid = 0;
|
pid_t wpid = 0;
|
||||||
pid_t wait_pid = 0;
|
pid_t wait_pid = 0;
|
||||||
@@ -1699,8 +1698,6 @@ int mch_call_shell(char_u *cmd, int options, char_u *extra_shell_arg)
|
|||||||
# endif
|
# endif
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
int argc;
|
|
||||||
char_u *p_shcf_copy = NULL;
|
|
||||||
int i;
|
int i;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
int pty_master_fd = -1; /* for pty's */
|
int pty_master_fd = -1; /* for pty's */
|
||||||
@@ -1710,19 +1707,11 @@ int mch_call_shell(char_u *cmd, int options, char_u *extra_shell_arg)
|
|||||||
char envbuf[50];
|
char envbuf[50];
|
||||||
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
|
int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
|
||||||
|
|
||||||
newcmd = vim_strsave(p_sh);
|
|
||||||
if (newcmd == NULL) /* out of memory */
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
out_flush();
|
out_flush();
|
||||||
if (options & SHELL_COOKED)
|
if (options & SHELL_COOKED)
|
||||||
settmode(TMODE_COOK); /* set to normal mode */
|
settmode(TMODE_COOK); /* set to normal mode */
|
||||||
|
|
||||||
// Count the number of arguments for the shell
|
argv = shell_build_argv(cmd, extra_shell_arg);
|
||||||
p = newcmd;
|
|
||||||
argc = shell_count_argc(&p);
|
|
||||||
p = newcmd;
|
|
||||||
argv = shell_build_argv(argc, cmd, extra_shell_arg, &p, &p_shcf_copy);
|
|
||||||
|
|
||||||
if (argv == NULL) {
|
if (argv == NULL) {
|
||||||
goto error;
|
goto error;
|
||||||
@@ -2304,15 +2293,13 @@ finished:
|
|||||||
MSG_PUTS(_("\nCommand terminated\n"));
|
MSG_PUTS(_("\nCommand terminated\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vim_free(argv);
|
shell_free_argv(argv);
|
||||||
vim_free(p_shcf_copy);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (!did_settmode)
|
if (!did_settmode)
|
||||||
if (tmode == TMODE_RAW)
|
if (tmode == TMODE_RAW)
|
||||||
settmode(TMODE_RAW); /* set to raw mode */
|
settmode(TMODE_RAW); /* set to raw mode */
|
||||||
resettitle();
|
resettitle();
|
||||||
vim_free(newcmd);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user