nnn

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 1a5a7da8ebec6c5b0848592e352fa8be075cf09c
parent d4575e99c8576af311cfb3f8d580cf698515a742
Author: Arun <engineerarun@gmail.com>
Date:   Sat, 28 Jan 2023 08:22:52 +0530

Merge pull request #1570 from KlzXS/general_simplification

Second attempt at #1566
Diffstat:
Msrc/nnn.c | 140++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 78 insertions(+), 62 deletions(-)

diff --git a/src/nnn.c b/src/nnn.c @@ -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 @@ -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 [:]", @@ -4425,92 +4425,108 @@ 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) { - fdout = create_tmp_file(); - if (fdout == -1) - return FALSE; + /* + * 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) { + DPRINTF_S("invalid get_ouptput() call"); + return FALSE; } - if (multi) { - cmd = parseargs(file, argv, &index); - if (!cmd) + /* Setup file descriptors for child command */ + if (!have_file && page) { + // Case 2 + fdout = create_tmp_file(); + if (fdout == -1) 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); + close(cmd_in_fd); + dup2(cmd_out_fd, STDOUT_FILENO); + dup2(cmd_out_fd, STDERR_FILENO); + close(cmd_out_fd); + + spawn(file, arg1, arg2, 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; } /* @@ -4536,7 +4552,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); @@ -4683,7 +4699,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) { @@ -5083,7 +5099,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) { @@ -5179,7 +5195,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 @@ -6325,7 +6341,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(); @@ -7045,11 +7061,11 @@ nochange: 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 */ - && get_output("file", "-bL", newpath, -1, FALSE, FALSE) + && get_output("file", "-bL", newpath, -1, FALSE) && strstr(g_buf, "text") #endif ) {