1 #include <sys/select.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <signal.h> 6 #include "pager.h" 7 #include "run-command.h" 8 #include "sigchain.h" 9 #include "subcmd-config.h" 10 11 /* 12 * This is split up from the rest of git so that we can do 13 * something different on Windows. 14 */ 15 16 static int spawned_pager; 17 18 void pager_init(const char *pager_env) 19 { 20 subcmd_config.pager_env = pager_env; 21 } 22 23 static void pager_preexec(void) 24 { 25 /* 26 * Work around bug in "less" by not starting it until we 27 * have real input 28 */ 29 fd_set in; 30 31 FD_ZERO(&in); 32 FD_SET(0, &in); 33 select(1, &in, NULL, &in, NULL); 34 35 setenv("LESS", "FRSX", 0); 36 } 37 38 static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; 39 static struct child_process pager_process; 40 41 static void wait_for_pager(void) 42 { 43 fflush(stdout); 44 fflush(stderr); 45 /* signal EOF to pager */ 46 close(1); 47 close(2); 48 finish_command(&pager_process); 49 } 50 51 static void wait_for_pager_signal(int signo) 52 { 53 wait_for_pager(); 54 sigchain_pop(signo); 55 raise(signo); 56 } 57 58 void setup_pager(void) 59 { 60 const char *pager = getenv(subcmd_config.pager_env); 61 62 if (!isatty(1)) 63 return; 64 if (!pager) 65 pager = getenv("PAGER"); 66 if (!(pager || access("/usr/bin/pager", X_OK))) 67 pager = "/usr/bin/pager"; 68 if (!(pager || access("/usr/bin/less", X_OK))) 69 pager = "/usr/bin/less"; 70 if (!pager) 71 pager = "cat"; 72 if (!*pager || !strcmp(pager, "cat")) 73 return; 74 75 spawned_pager = 1; /* means we are emitting to terminal */ 76 77 /* spawn the pager */ 78 pager_argv[2] = pager; 79 pager_process.argv = pager_argv; 80 pager_process.in = -1; 81 pager_process.preexec_cb = pager_preexec; 82 83 if (start_command(&pager_process)) 84 return; 85 86 /* original process continues, but writes to the pipe */ 87 dup2(pager_process.in, 1); 88 if (isatty(2)) 89 dup2(pager_process.in, 2); 90 close(pager_process.in); 91 92 /* this makes sure that the parent terminates after the pager */ 93 sigchain_push_common(wait_for_pager_signal); 94 atexit(wait_for_pager); 95 } 96 97 int pager_in_use(void) 98 { 99 return spawned_pager; 100 } 101