aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/nnn.c124
1 files changed, 69 insertions, 55 deletions
diff --git a/src/nnn.c b/src/nnn.c
index ffca34a..90146b6 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -186,6 +186,7 @@ disabledbg()
#define CTX_MAX 4
#define DOT_FILTER_LEN 7
#define ASCII_MAX 128
+#define EXEC_ARGS_MAX 8
/* Entry flags */
#define DIR_OR_LINK_TO_DIR 0x1
@@ -198,6 +199,7 @@ disabledbg()
#define F_NOTRACE 0x04 /* suppress stdout and strerr (no traces) */
#define F_SIGINT 0x08 /* restore default SIGINT handler */
#define F_EDITOR 0x10 /* spawn the editor */
+#define F_MULTI 0x20 /* first arg can be combination of args */
#define F_NORMAL 0x80 /* spawn child process in non-curses regular CLI mode */
/* CRC8 macros */
@@ -491,7 +493,7 @@ static const char * const envs[] = {
/* Forward declarations */
static void redraw(char *path);
-static void spawn(const char *file, const char *arg1, const char *arg2, const char *dir, uchar flag);
+static void spawn(char *file, char *arg1, char *arg2, const char *dir, uchar flag);
static int (*nftw_fn)(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
/* Functions */
@@ -969,23 +971,77 @@ static bool initcurses(void)
return TRUE;
}
+/* NOTE: There's no NULL check here */
+
+static int parseargs(char *line, char **argv)
+{
+ int count = 0;
+
+ argv[count++] = line;
+
+ while (*line) {
+ if (isblank(*line)) {
+ *line++ = '\0';
+
+ if (!*line)
+ return count;
+
+ argv[count++] = line;
+ if (count == EXEC_ARGS_MAX)
+ return -1;
+ }
+
+ ++line;
+ }
+
+ return count;
+}
+
/*
* Spawns a child process. Behaviour can be controlled using flag.
* Limited to 2 arguments to a program, flag works on bit set.
*/
-static void spawn(const char *file, const char *arg1, const char *arg2, const char *dir, uchar flag)
+static void spawn(char *file, char *arg1, char *arg2, const char *dir, uchar flag)
{
pid_t pid;
int status;
- const char *tmp;
+ char *argv[EXEC_ARGS_MAX] = {0};
+ char *cmd = NULL;
+
+ if (!file || !file[0])
+ return;
/* Swap args if the first arg is NULL and second isn't */
if (!arg1 && arg2) {
- tmp = arg1;
arg1 = arg2;
- arg2 = tmp;
+ arg2 = NULL;
+ }
+
+ if (flag & F_MULTI) {
+ size_t len = strlen(file) + 1;
+ cmd = (char *)malloc(len);
+ if (!cmd) {
+ DPRINTF_S("spawn: malloc()!");
+ return;
+ }
+
+ xstrlcpy(cmd, file, len);
+ argv[0] = file;
+ status = parseargs(cmd, argv);
+ if (status == -1 || status > (EXEC_ARGS_MAX - 2)) { /* arg1 and last NULL */
+ free(cmd);
+ DPRINTF_S("spawn: NULL or too many args");
+ return;
+ }
+
+ argv[status] = arg1;
+ } else {
+ argv[0] = file;
+ argv[1] = arg1;
+ argv[2] = arg2;
}
+
if (flag & F_NORMAL)
exitcurses();
@@ -1012,7 +1068,7 @@ static void spawn(const char *file, const char *arg1, const char *arg2, const ch
if (flag & F_SIGINT)
signal(SIGINT, SIG_DFL);
- execlp(file, file, arg1, arg2, NULL);
+ execvp(*argv, argv);
_exit(1);
} else {
if (!(flag & F_NOWAIT))
@@ -1029,50 +1085,9 @@ static void spawn(const char *file, const char *arg1, const char *arg2, const ch
initcurses();
}
}
- }
-}
-/*
- * Quotes argument and spawns a shell command
- * Uses g_buf
- */
-static bool quote_run_sh_cmd(const char *cmd, const char *arg, const char *path)
-{
- const char *ptr;
- size_t r;
-
- if (!cmd)
- return FALSE;
-
- r = xstrlcpy(g_buf, cmd, CMD_LEN_MAX);
-
- if (arg) {
- if (r >= CMD_LEN_MAX - 4) { /* space for at least 4 chars - space'c' */
- printmsg(messages[STR_UNSAFE]);
- return FALSE;
- }
-
- for (ptr = arg; *ptr; ++ptr)
- if (*ptr == '\'') {
- printmsg(messages[STR_UNSAFE]);
- return FALSE;
- }
-
- g_buf[r - 1] = ' ';
- g_buf[r] = '\'';
- r += xstrlcpy(g_buf + r + 1, arg, CMD_LEN_MAX - 1 - r);
- if (r >= CMD_LEN_MAX - 1) {
- printmsg(messages[STR_UNSAFE]);
- return FALSE;
- }
-
- g_buf[r] = '\'';
- g_buf[r + 1] = '\0';
+ free(cmd);
}
-
- DPRINTF_S(g_buf);
- spawn("sh", "-c", g_buf, path, F_NORMAL | F_EDITOR);
- return TRUE;
}
/* Get program name from env var, else return fallback program */
@@ -2318,7 +2333,7 @@ static bool show_mediainfo(const char *fpath, const char *arg)
return TRUE;
}
-static bool handle_archive(const char *fpath, const char *arg, const char *dir)
+static bool handle_archive(char *fpath, char *arg, const char *dir)
{
if (!getutil(utils[ATOOL]))
return FALSE;
@@ -3008,8 +3023,8 @@ nochange:
get_output(g_buf, CMD_LEN_MAX, "file", FILE_OPTS, newpath, FALSE)
&& g_buf[0] == 't' && g_buf[1] == 'e' && g_buf[2] == 'x'
&& g_buf[3] == g_buf[0] && g_buf[4] == '/') {
- if (!quote_run_sh_cmd(editor, newpath, path))
- goto nochange;
+ spawn(editor, newpath, NULL, path,
+ F_NORMAL | F_EDITOR | F_MULTI);
continue;
}
@@ -3355,8 +3370,8 @@ nochange:
r = show_help(path);
break;
case SEL_RUNEDIT:
- if (!quote_run_sh_cmd(editor, dents[cur].name, path))
- goto nochange;
+ spawn(editor, dents[cur].name, NULL, path,
+ F_NORMAL | F_EDITOR |F_MULTI);
break;
case SEL_RUNPAGE:
spawn(pager, pager_arg, dents[cur].name, path, F_NORMAL);
@@ -3371,8 +3386,7 @@ nochange:
goto nochange;
}
- if (!quote_run_sh_cmd(editor, notepath, NULL))
- goto nochange;
+ spawn(editor, notepath, NULL, path, F_NORMAL | F_EDITOR |F_MULTI);
break;
}
default: /* SEL_LOCK */