Merge branch 'jc/maint-split-diff-metainfo'
[git] / pager.c
1 #include "cache.h"
2 #include "run-command.h"
3 #include "sigchain.h"
4
5 /*
6  * This is split up from the rest of git so that we can do
7  * something different on Windows.
8  */
9
10 static int spawned_pager;
11
12 #ifndef __MINGW32__
13 static void pager_preexec(void)
14 {
15         /*
16          * Work around bug in "less" by not starting it until we
17          * have real input
18          */
19         fd_set in;
20
21         FD_ZERO(&in);
22         FD_SET(0, &in);
23         select(1, &in, NULL, &in, NULL);
24
25         setenv("LESS", "FRSX", 0);
26 }
27 #endif
28
29 static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
30 static struct child_process pager_process;
31
32 static void wait_for_pager(void)
33 {
34         fflush(stdout);
35         fflush(stderr);
36         /* signal EOF to pager */
37         close(1);
38         close(2);
39         finish_command(&pager_process);
40 }
41
42 static void wait_for_pager_signal(int signo)
43 {
44         wait_for_pager();
45         sigchain_pop(signo);
46         raise(signo);
47 }
48
49 void setup_pager(void)
50 {
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         /* spawn the pager */
70         pager_argv[2] = pager;
71         pager_process.argv = pager_argv;
72         pager_process.in = -1;
73 #ifndef __MINGW32__
74         pager_process.preexec_cb = pager_preexec;
75 #endif
76         if (start_command(&pager_process))
77                 return;
78
79         /* original process continues, but writes to the pipe */
80         dup2(pager_process.in, 1);
81         if (isatty(2))
82                 dup2(pager_process.in, 2);
83         close(pager_process.in);
84
85         /* this makes sure that the parent terminates after the pager */
86         sigchain_push_common(wait_for_pager_signal);
87         atexit(wait_for_pager);
88 }
89
90 int pager_in_use(void)
91 {
92         const char *env;
93
94         if (spawned_pager)
95                 return 1;
96
97         env = getenv("GIT_PAGER_IN_USE");
98         return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
99 }