summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 5679054)
raw | patch | inline | side by side (parent: 5679054)
author | Jonas Fonseca <fonseca@diku.dk> | |
Sat, 10 Jan 2009 03:21:44 +0000 (22:21 -0500) | ||
committer | Jonas Fonseca <fonseca@diku.dk> | |
Tue, 13 Jan 2009 21:55:20 +0000 (22:55 +0100) |
tig.c | patch | blob | history |
index 1fd4bc9c14afb1e073afea5f9b6534661adcae47..eab037fb7bcceef25029a09eae6674b1c26218a4 100644 (file)
--- a/tig.c
+++ b/tig.c
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
FORMAT_NONE /* No replacement should be performed. */
};
-static bool format_command(char dst[], const char *src[], enum format_flags flags);
static bool format_argv(const char *dst[], const char *src[], enum format_flags flags);
struct int_map {
return suffixlen < len ? strcmp(str + len - suffixlen, suffix) : -1;
}
-/* Shell quoting
- *
- * NOTE: The following is a slightly modified copy of the git project's shell
- * quoting routines found in the quote.c file.
- *
- * Help to copy the thing properly quoted for the shell safety. any single
- * quote is replaced with '\'', any exclamation point is replaced with '\!',
- * and the whole thing is enclosed in a
- *
- * E.g.
- * original sq_quote result
- * name ==> name ==> 'name'
- * a b ==> a b ==> 'a b'
- * a'b ==> a'\''b ==> 'a'\''b'
- * a!b ==> a'\!'b ==> 'a'\!'b'
- */
-
-static size_t
-sq_quote(char buf[SIZEOF_STR], size_t bufsize, const char *src)
-{
- char c;
-
-#define BUFPUT(x) do { if (bufsize < SIZEOF_STR) buf[bufsize++] = (x); } while (0)
-
- BUFPUT('\'');
- while ((c = *src++)) {
- if (c == '\'' || c == '!') {
- BUFPUT('\'');
- BUFPUT('\\');
- BUFPUT(c);
- BUFPUT('\'');
- } else {
- BUFPUT(c);
- }
- }
- BUFPUT('\'');
-
- if (bufsize < SIZEOF_STR)
- buf[bufsize] = 0;
-
- return bufsize;
-}
static bool
argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
struct io {
enum io_type type; /* The requested type of pipe. */
const char *dir; /* Directory from which to execute. */
- FILE *pid; /* Pipe for reading or writing. */
+ pid_t pid; /* Pipe for reading or writing. */
int pipe; /* Pipe end for reading or writing. */
int error; /* Error status. */
const char *argv[SIZEOF_ARG]; /* Shell command arguments. */
reset_io(struct io *io)
{
io->pipe = -1;
- io->pid = NULL;
+ io->pid = 0;
io->buf = io->bufpos = NULL;
io->bufalloc = io->bufsize = 0;
io->error = 0;
return io->pipe != -1;
}
+static bool
+kill_io(struct io *io)
+{
+ return kill(io->pid, SIGKILL) != -1;
+}
+
static bool
done_io(struct io *io)
{
- free(io->buf);
- if (io->type == IO_FD)
+ pid_t pid = io->pid;
+
+ if (io->pipe != -1)
close(io->pipe);
- else if (io->type == IO_RD || io->type == IO_WR)
- pclose(io->pid);
+ free(io->buf);
reset_io(io);
+
+ while (pid > 0) {
+ int status;
+ pid_t waiting = waitpid(pid, &status, 0);
+
+ if (waiting < 0) {
+ if (errno == EINTR)
+ continue;
+ report("waitpid failed (%s)", strerror(errno));
+ return FALSE;
+ }
+
+ return waiting == pid &&
+ !WIFSIGNALED(status) &&
+ WIFEXITED(status) &&
+ !WEXITSTATUS(status);
+ }
+
return TRUE;
}
static bool
start_io(struct io *io)
{
- char buf[SIZEOF_STR * 2];
- size_t bufpos = 0;
+ int pipefds[2] = { -1, -1 };
if (io->type == IO_FD)
return TRUE;
- if (io->dir && *io->dir &&
- !string_format_from(buf, &bufpos, "cd %s;", io->dir))
+ if ((io->type == IO_RD || io->type == IO_WR) &&
+ pipe(pipefds) < 0)
return FALSE;
- if (!format_command(buf + bufpos, io->argv, FORMAT_NONE))
- return FALSE;
+ if ((io->pid = fork())) {
+ if (pipefds[!(io->type == IO_WR)] != -1)
+ close(pipefds[!(io->type == IO_WR)]);
+ if (io->pid != -1) {
+ io->pipe = pipefds[!!(io->type == IO_WR)];
+ return TRUE;
+ }
+
+ } else {
+ if (io->type != IO_FG) {
+ int devnull = open("/dev/null", O_RDWR);
+ int readfd = io->type == IO_WR ? pipefds[0] : devnull;
+ int writefd = io->type == IO_RD ? pipefds[1] : devnull;
+
+ dup2(readfd, STDIN_FILENO);
+ dup2(writefd, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+
+ close(devnull);
+ if (pipefds[0] != -1)
+ close(pipefds[0]);
+ if (pipefds[1] != -1)
+ close(pipefds[1]);
+ }
- if (io->type == IO_FG || io->type == IO_BG)
- return system(buf) == 0;
+ if (io->dir && *io->dir && chdir(io->dir) == -1)
+ die("Failed to change directory: %s", strerror(errno));
- io->pid = popen(buf, io->type == IO_RD ? "r" : "w");
- if (!io->pid)
- return FALSE;
- io->pipe = fileno(io->pid);
- return io->pipe != -1;
+ execvp(io->argv[0], (char *const*) io->argv);
+ die("Failed to execute program: %s", strerror(errno));
+ }
+
+ if (pipefds[!!(io->type == IO_WR)] != -1)
+ close(pipefds[!!(io->type == IO_WR)]);
+ return FALSE;
}
static bool
@@ -2554,31 +2559,6 @@ format_argv(const char *dst_argv[], const char *src_argv[], enum format_flags fl
return src_argv[argc] == NULL;
}
-static bool
-format_command(char dst[], const char *src_argv[], enum format_flags flags)
-{
- const char *dst_argv[SIZEOF_ARG * 2] = { NULL };
- int bufsize = 0;
- int argc;
-
- if (!format_argv(dst_argv, src_argv, flags)) {
- free_argv(dst_argv);
- return FALSE;
- }
-
- for (argc = 0; dst_argv[argc] && bufsize < SIZEOF_STR; argc++) {
- if (bufsize > 0)
- dst[bufsize++] = ' ';
- bufsize = sq_quote(dst, bufsize, dst_argv[argc]);
- }
-
- if (bufsize < SIZEOF_STR)
- dst[bufsize] = 0;
- free_argv(dst_argv);
-
- return src_argv[argc] == NULL && bufsize < SIZEOF_STR;
-}
-
static void
end_update(struct view *view, bool force)
{
if (!force)
return;
set_nonblocking_input(FALSE);
+ if (force)
+ kill_io(view->pipe);
done_io(view->pipe);
view->pipe = NULL;
}