1#include "cache.h"
2
3/*
4 * This is split up from the rest of git so that we can do
5 * something different on Windows.
6 */
7
8static int spawned_pager;
9
10#ifndef __MINGW32__
11static void run_pager(const char *pager)
12{
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
23 execlp(pager, pager, NULL);
24 execl("/bin/sh", "sh", "-c", pager, NULL);
25}
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
44
45void setup_pager(void)
46{
47#ifndef __MINGW32__
48 pid_t pid;
49 int fd[2];
50#endif
51 const char *pager = getenv("GIT_PAGER");
52
53 if (!isatty(1))
54 return;
55 if (!pager) {
56 if (!pager_program)
57 git_config(git_default_config, NULL);
58 pager = pager_program;
59 }
60 if (!pager)
61 pager = getenv("PAGER");
62 if (!pager)
63 pager = "less";
64 else if (!*pager || !strcmp(pager, "cat"))
65 return;
66
67 spawned_pager = 1; /* means we are emitting to terminal */
68
69#ifndef __MINGW32__
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);
82 dup2(fd[1], 2);
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
93 setenv("LESS", "FRSX", 0);
94 run_pager(pager);
95 die("unable to execute pager '%s'", pager);
96 exit(255);
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
111}
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}