run-command: add pre-exec callback
[git/git.git] / pager.c
CommitLineData
f67b45f8
LT
1#include "cache.h"
2
3/*
bfdd9ffd
JS
4 * This is split up from the rest of git so that we can do
5 * something different on Windows.
f67b45f8
LT
6 */
7
6e9af863
JK
8static int spawned_pager;
9
bfdd9ffd 10#ifndef __MINGW32__
402461aa 11static void run_pager(const char *pager)
f67b45f8 12{
35ce8622
LT
13 /*
14 * Work around bug in "less" by not starting it until we
15 * have real input
16 */
17 fd_set in;
18
19 FD_ZERO(&in);
20 FD_SET(0, &in);
21 select(1, &in, NULL, &in, NULL);
22
402461aa 23 execlp(pager, pager, NULL);
34fd1c9a 24 execl("/bin/sh", "sh", "-c", pager, NULL);
f67b45f8 25}
bfdd9ffd
JS
26#else
27#include "run-command.h"
28
29static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30static struct child_process pager_process = {
31 .argv = pager_argv,
32 .in = -1
33};
34static void wait_for_pager(void)
35{
36 fflush(stdout);
37 fflush(stderr);
38 /* signal EOF to pager */
39 close(1);
40 close(2);
41 finish_command(&pager_process);
42}
43#endif
f67b45f8
LT
44
45void setup_pager(void)
46{
bfdd9ffd 47#ifndef __MINGW32__
f67b45f8
LT
48 pid_t pid;
49 int fd[2];
bfdd9ffd 50#endif
c27d205a 51 const char *pager = getenv("GIT_PAGER");
f67b45f8
LT
52
53 if (!isatty(1))
54 return;
cad3a205
JH
55 if (!pager) {
56 if (!pager_program)
ef90d6d4 57 git_config(git_default_config, NULL);
54adf370 58 pager = pager_program;
cad3a205 59 }
c27d205a
ML
60 if (!pager)
61 pager = getenv("PAGER");
402461aa
JS
62 if (!pager)
63 pager = "less";
caef71a5 64 else if (!*pager || !strcmp(pager, "cat"))
402461aa
JS
65 return;
66
6e9af863 67 spawned_pager = 1; /* means we are emitting to terminal */
85fb65ed 68
bfdd9ffd 69#ifndef __MINGW32__
f67b45f8
LT
70 if (pipe(fd) < 0)
71 return;
72 pid = fork();
73 if (pid < 0) {
74 close(fd[0]);
75 close(fd[1]);
76 return;
77 }
78
79 /* return in the child */
80 if (!pid) {
81 dup2(fd[1], 1);
61b80509 82 dup2(fd[1], 2);
f67b45f8
LT
83 close(fd[0]);
84 close(fd[1]);
85 return;
86 }
87
88 /* The original process turns into the PAGER */
89 dup2(fd[0], 0);
90 close(fd[0]);
91 close(fd[1]);
92
0abc0260 93 setenv("LESS", "FRSX", 0);
402461aa 94 run_pager(pager);
34fd1c9a 95 die("unable to execute pager '%s'", pager);
f67b45f8 96 exit(255);
bfdd9ffd
JS
97#else
98 /* spawn the pager */
99 pager_argv[2] = pager;
100 if (start_command(&pager_process))
101 return;
102
103 /* original process continues, but writes to the pipe */
104 dup2(pager_process.in, 1);
105 dup2(pager_process.in, 2);
106 close(pager_process.in);
107
108 /* this makes sure that the parent terminates after the pager */
109 atexit(wait_for_pager);
110#endif
f67b45f8 111}
6e9af863
JK
112
113int pager_in_use(void)
114{
115 const char *env;
116
117 if (spawned_pager)
118 return 1;
119
120 env = getenv("GIT_PAGER_IN_USE");
121 return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
122}