brintos

brintos / linux-shallow public Read only

0
0
Text · 2.5 KiB · e3d47b5 Raw
130 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <sys/select.h>3#include <stdlib.h>4#include <stdio.h>5#include <string.h>6#include <signal.h>7#include <sys/ioctl.h>8#include "pager.h"9#include "run-command.h"10#include "sigchain.h"11#include "subcmd-config.h"12 13/*14 * This is split up from the rest of git so that we can do15 * something different on Windows.16 */17 18static int spawned_pager;19static int pager_columns;20 21void pager_init(const char *pager_env)22{23	subcmd_config.pager_env = pager_env;24}25 26static const char *forced_pager;27 28void force_pager(const char *pager)29{30	forced_pager = pager;31}32 33static void pager_preexec(void)34{35	/*36	 * Work around bug in "less" by not starting it until we37	 * have real input38	 */39	fd_set in;40	fd_set exception;41 42	FD_ZERO(&in);43	FD_ZERO(&exception);44	FD_SET(0, &in);45	FD_SET(0, &exception);46	select(1, &in, NULL, &exception, NULL);47 48	setenv("LESS", "FRSX", 0);49}50 51static const char *pager_argv[] = { "sh", "-c", NULL, NULL };52static struct child_process pager_process;53 54static void wait_for_pager(void)55{56	fflush(stdout);57	fflush(stderr);58	/* signal EOF to pager */59	close(1);60	close(2);61	finish_command(&pager_process);62}63 64static void wait_for_pager_signal(int signo)65{66	wait_for_pager();67	sigchain_pop(signo);68	raise(signo);69}70 71void setup_pager(void)72{73	const char *pager = getenv(subcmd_config.pager_env);74	struct winsize sz;75 76	if (forced_pager)77		pager = forced_pager;78	if (!isatty(1) && !forced_pager)79		return;80	if (ioctl(1, TIOCGWINSZ, &sz) == 0)81		pager_columns = sz.ws_col;82	if (!pager)83		pager = getenv("PAGER");84	if (!(pager || access("/usr/bin/pager", X_OK)))85		pager = "/usr/bin/pager";86	if (!(pager || access("/usr/bin/less", X_OK)))87		pager = "/usr/bin/less";88	if (!pager)89		pager = "cat";90	if (!*pager || !strcmp(pager, "cat"))91		return;92 93	spawned_pager = 1; /* means we are emitting to terminal */94 95	/* spawn the pager */96	pager_argv[2] = pager;97	pager_process.argv = pager_argv;98	pager_process.in = -1;99	pager_process.preexec_cb = pager_preexec;100 101	if (start_command(&pager_process))102		return;103 104	/* original process continues, but writes to the pipe */105	dup2(pager_process.in, 1);106	if (isatty(2))107		dup2(pager_process.in, 2);108	close(pager_process.in);109 110	/* this makes sure that the parent terminates after the pager */111	sigchain_push_common(wait_for_pager_signal);112	atexit(wait_for_pager);113}114 115int pager_in_use(void)116{117	return spawned_pager;118}119 120int pager_get_columns(void)121{122	char *s;123 124	s = getenv("COLUMNS");125	if (s)126		return atoi(s);127 128	return (pager_columns ? pager_columns : 80) - 2;129}130