diff options
Diffstat (limited to 'tools/lib/subcmd/pager.c')
| -rw-r--r-- | tools/lib/subcmd/pager.c | 100 | 
1 files changed, 100 insertions, 0 deletions
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c new file mode 100644 index 000000000000..d50f3b58606b --- /dev/null +++ b/tools/lib/subcmd/pager.c @@ -0,0 +1,100 @@ +#include <sys/select.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include "pager.h" +#include "run-command.h" +#include "sigchain.h" +#include "subcmd-config.h" + +/* + * This is split up from the rest of git so that we can do + * something different on Windows. + */ + +static int spawned_pager; + +void pager_init(const char *pager_env) +{ +	subcmd_config.pager_env = pager_env; +} + +static void pager_preexec(void) +{ +	/* +	 * Work around bug in "less" by not starting it until we +	 * have real input +	 */ +	fd_set in; + +	FD_ZERO(&in); +	FD_SET(0, &in); +	select(1, &in, NULL, &in, NULL); + +	setenv("LESS", "FRSX", 0); +} + +static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; +static struct child_process pager_process; + +static void wait_for_pager(void) +{ +	fflush(stdout); +	fflush(stderr); +	/* signal EOF to pager */ +	close(1); +	close(2); +	finish_command(&pager_process); +} + +static void wait_for_pager_signal(int signo) +{ +	wait_for_pager(); +	sigchain_pop(signo); +	raise(signo); +} + +void setup_pager(void) +{ +	const char *pager = getenv(subcmd_config.pager_env); + +	if (!isatty(1)) +		return; +	if (!pager) +		pager = getenv("PAGER"); +	if (!(pager || access("/usr/bin/pager", X_OK))) +		pager = "/usr/bin/pager"; +	if (!(pager || access("/usr/bin/less", X_OK))) +		pager = "/usr/bin/less"; +	if (!pager) +		pager = "cat"; +	if (!*pager || !strcmp(pager, "cat")) +		return; + +	spawned_pager = 1; /* means we are emitting to terminal */ + +	/* spawn the pager */ +	pager_argv[2] = pager; +	pager_process.argv = pager_argv; +	pager_process.in = -1; +	pager_process.preexec_cb = pager_preexec; + +	if (start_command(&pager_process)) +		return; + +	/* original process continues, but writes to the pipe */ +	dup2(pager_process.in, 1); +	if (isatty(2)) +		dup2(pager_process.in, 2); +	close(pager_process.in); + +	/* this makes sure that the parent terminates after the pager */ +	sigchain_push_common(wait_for_pager_signal); +	atexit(wait_for_pager); +} + +int pager_in_use(void) +{ +	return spawned_pager; +}  |