Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General simplification #1566

Merged
merged 4 commits into from
Jan 15, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 92 additions & 61 deletions src/nnn.c
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ static void move_cursor(int target, int ignore_scrolloff);
static char *load_input(int fd, const char *path);
static int set_sort_flags(int r);
static void statusbar(char *path);
static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool multi, bool page);
static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool page);
#ifndef NOFIFO
static void notify_fifo(bool force);
#endif
Expand Down Expand Up @@ -3188,7 +3188,7 @@ static void showfilterinfo(void)

i = getorderstr(info);

if (cfg.fileinfo && ndents && get_output("file", "-b", pdents[cur].name, -1, FALSE, FALSE))
if (cfg.fileinfo && ndents && get_output("file", "-b", pdents[cur].name, -1, FALSE))
mvaddstr(xlines - 2, 2, g_buf);
else {
snprintf(info + i, REGEX_MAX - i - 1, " %s [/], %4s [:]",
Expand Down Expand Up @@ -4425,92 +4425,123 @@ static void set_smart_ctx(int ctx, char *nextpath, char **path, char *file, char
}

/*
* Gets only a single line (that's what we need for now) or shows full command output in pager.
* Uses g_buf internally.
* This function does one of the following depending on the values of `fdout` and `page`:
* 1) fdout == -1 && !page: Write up to CMD_LEN_MAX bytes of command output into g_buf
* 2) fdout == -1 && page: Create a temp file, write full command output into it and show in pager.
* 3) fdout != -1 && !page: Write full command output into the provided file.
* 4) fdout != -1 && page: Don't use! Returns FASLE.
*
* g_buf is modified only in case 1.
* g_tmpfpath is modified only in case 2.
*/
static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool multi, bool page)
static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool page)
{
pid_t pid;
int pipefd[2];
int index = 0, flags;
bool ret = FALSE;
bool tmpfile = ((fdout == -1) && page);
char *argv[EXEC_ARGS_MAX] = {0};
char *cmd = NULL;
int fd = -1;
bool have_file = fdout != -1;
int cmd_in_fd = -1;
int cmd_out_fd = -1;
ssize_t len;

if (tmpfile) {
/*
* In this case the logic of the function dictates that we should write the output of the command
* to `fd` and show it in the pager. But since we didn't open the file descriptor we have no right
* to close it, the caller must do it. We don't even know the path to pass to the pager and
* it's a real hassle to get it. In general this just invites problems so we are blocking it.
*/
if (have_file && page)
return FALSE;

/* Setup file descriptors for child command */
if (!have_file && page) {
// Case 2
fdout = create_tmp_file();
if (fdout == -1)
return FALSE;
}

if (multi) {
cmd = parseargs(file, argv, &index);
if (!cmd)
return FALSE;
} else
argv[index++] = file;

argv[index] = arg1;
argv[++index] = arg2;
cmd_in_fd = STDIN_FILENO;
cmd_out_fd = fdout;
} else if (have_file) {
// Case 3
cmd_in_fd = STDIN_FILENO;
cmd_out_fd = fdout;
} else {
// Case 1
if (pipe(pipefd) == -1)
errexit();

if (pipe(pipefd) == -1) {
free(cmd);
errexit();
}
for (index = 0; index < 2; ++index) {
/* Get previous flags */
flags = fcntl(pipefd[index], F_GETFL, 0);

for (index = 0; index < 2; ++index) {
/* Get previous flags */
flags = fcntl(pipefd[index], F_GETFL, 0);
/* Set bit for non-blocking flag */
flags |= O_NONBLOCK;

/* Set bit for non-blocking flag */
flags |= O_NONBLOCK;
/* Change flags on fd */
fcntl(pipefd[index], F_SETFL, flags);
}

/* Change flags on fd */
fcntl(pipefd[index], F_SETFL, flags);
cmd_in_fd = pipefd[0];
cmd_out_fd = pipefd[1];
}

pid = fork();
if (pid == 0) {
/* In child */
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[1], STDERR_FILENO);
close(pipefd[1]);
execvp(*argv, argv);
char *bufptr = file;

close(cmd_in_fd);
dup2(cmd_out_fd, STDOUT_FILENO);
dup2(cmd_out_fd, STDERR_FILENO);
close(cmd_out_fd);

if (bufptr && arg1) {
char argbuf[CMD_LEN_MAX];

len = xstrsncpy(argbuf, file, xstrlen(file) + 1);
argbuf[len - 1] = ' ';
bufptr = argbuf + len;
len = xstrsncpy(bufptr, arg1, xstrlen(arg1) + 1);
if (arg2) {
bufptr[len - 1] = ' ';
xstrsncpy(bufptr + len, arg2, xstrlen(arg2) + 1);
}

bufptr = argbuf;
}

spawn(utils[UTIL_SH_EXEC], bufptr, NULL, NULL, F_MULTI);
_exit(EXIT_SUCCESS);
}

/* In parent */
waitpid(pid, NULL, 0);
close(pipefd[1]);
free(cmd);

while ((len = read(pipefd[0], g_buf, CMD_LEN_MAX - 1)) > 0) {
ret = TRUE;
if (fdout == -1) /* Read only the first line of output to buffer */
break;
if (write(fdout, g_buf, len) != len)
break;
}
/* Do what each case should do */
if (!have_file && page) {
// Case 2
close(fdout);

close(pipefd[0]);
if (!page)
return ret;
spawn(pager, g_tmpfpath, NULL, NULL, F_CLI | F_TTY);

if (tmpfile) {
close(fdout);
close(fd);
unlink(g_tmpfpath);
return TRUE;
}

spawn(pager, g_tmpfpath, NULL, NULL, F_CLI | F_TTY);
if (have_file)
// Case 3
return TRUE;

if (tmpfile)
unlink(g_tmpfpath);
// Case 1
len = read(pipefd[0], g_buf, CMD_LEN_MAX - 1);
if (len > 0)
ret = TRUE;

return TRUE;
close(pipefd[0]);
close(pipefd[1]);
return ret;
}

/*
Expand All @@ -4536,7 +4567,7 @@ static bool show_stats(char *fpath)
return FALSE;

while (r)
get_output(cmds[--r], fpath, NULL, fd, TRUE, FALSE);
get_output(cmds[--r], fpath, NULL, fd, FALSE);

close(fd);

Expand Down Expand Up @@ -4683,7 +4714,7 @@ static bool handle_archive(char *fpath /* in-out param */, char op)
if (op == 'x') /* extract */
spawn(util, arg, fpath, NULL, F_NORMAL | F_MULTI);
else /* list */
get_output(util, arg, fpath, -1, TRUE, TRUE);
get_output(util, arg, fpath, -1, TRUE);

if (x_to) {
if (chdir(xdirname(fpath)) == -1) {
Expand Down Expand Up @@ -5083,7 +5114,7 @@ static void show_help(const char *path)

char *prog = xgetenv(env_cfg[NNN_HELP], NULL);
if (prog)
get_output(prog, NULL, NULL, fd, TRUE, FALSE);
get_output(prog, NULL, NULL, fd, FALSE);

start = end = helpstr;
while (*end) {
Expand Down Expand Up @@ -5179,7 +5210,7 @@ static void run_cmd_as_plugin(const char *file, char *runfile, uchar_t flags)
runfile = NULL;

if (flags & F_PAGE)
get_output(g_buf, runfile, NULL, -1, TRUE, TRUE);
get_output(g_buf, runfile, NULL, -1, TRUE);
else // F_NOTRACE
spawn(g_buf, runfile, NULL, NULL, flags);
} else
Expand Down Expand Up @@ -6325,7 +6356,7 @@ static void statusbar(char *path)

attron(COLOR_PAIR(cfg.curctx + 1));

if (cfg.fileinfo && get_output("file", "-b", pdents[cur].name, -1, FALSE, FALSE))
if (cfg.fileinfo && get_output("file", "-b", pdents[cur].name, -1, FALSE))
mvaddstr(xlines - 2, 2, g_buf);

tolastln();
Expand Down Expand Up @@ -7045,7 +7076,7 @@ static bool browse(char *ipath, const char *session, int pkey)

if (cfg.useeditor
#ifdef FILE_MIME_OPTS
&& get_output("file", FILE_MIME_OPTS, newpath, -1, FALSE, FALSE)
&& get_output("file", FILE_MIME_OPTS, newpath, -1, FALSE)
&& is_prefix(g_buf, "text/", 5)
#else
/* no MIME option; guess from description instead */
Expand Down