Linux Audio

Check our new training course

Real-Time Linux with PREEMPT_RT training

Feb 18-20, 2025
Register
Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2#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 do
 15 * 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 void pager_preexec(void)
 27{
 28	/*
 29	 * Work around bug in "less" by not starting it until we
 30	 * have real input
 31	 */
 32	fd_set in;
 33	fd_set exception;
 34
 35	FD_ZERO(&in);
 36	FD_ZERO(&exception);
 37	FD_SET(0, &in);
 38	FD_SET(0, &exception);
 39	select(1, &in, NULL, &exception, NULL);
 40
 41	setenv("LESS", "FRSX", 0);
 42}
 43
 44static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
 45static struct child_process pager_process;
 46
 47static void wait_for_pager(void)
 48{
 49	fflush(stdout);
 50	fflush(stderr);
 51	/* signal EOF to pager */
 52	close(1);
 53	close(2);
 54	finish_command(&pager_process);
 55}
 56
 57static void wait_for_pager_signal(int signo)
 58{
 59	wait_for_pager();
 60	sigchain_pop(signo);
 61	raise(signo);
 62}
 63
 64void setup_pager(void)
 65{
 66	const char *pager = getenv(subcmd_config.pager_env);
 67	struct winsize sz;
 68
 69	if (!isatty(1))
 70		return;
 71	if (ioctl(1, TIOCGWINSZ, &sz) == 0)
 72		pager_columns = sz.ws_col;
 73	if (!pager)
 74		pager = getenv("PAGER");
 75	if (!(pager || access("/usr/bin/pager", X_OK)))
 76		pager = "/usr/bin/pager";
 77	if (!(pager || access("/usr/bin/less", X_OK)))
 78		pager = "/usr/bin/less";
 79	if (!pager)
 80		pager = "cat";
 81	if (!*pager || !strcmp(pager, "cat"))
 82		return;
 83
 84	spawned_pager = 1; /* means we are emitting to terminal */
 85
 86	/* spawn the pager */
 87	pager_argv[2] = pager;
 88	pager_process.argv = pager_argv;
 89	pager_process.in = -1;
 90	pager_process.preexec_cb = pager_preexec;
 91
 92	if (start_command(&pager_process))
 93		return;
 94
 95	/* original process continues, but writes to the pipe */
 96	dup2(pager_process.in, 1);
 97	if (isatty(2))
 98		dup2(pager_process.in, 2);
 99	close(pager_process.in);
100
101	/* this makes sure that the parent terminates after the pager */
102	sigchain_push_common(wait_for_pager_signal);
103	atexit(wait_for_pager);
104}
105
106int pager_in_use(void)
107{
108	return spawned_pager;
109}
110
111int pager_get_columns(void)
112{
113	char *s;
114
115	s = getenv("COLUMNS");
116	if (s)
117		return atoi(s);
118
119	return (pager_columns ? pager_columns : 80) - 2;
120}