Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <sys/select.h>
0003 #include <stdlib.h>
0004 #include <stdio.h>
0005 #include <string.h>
0006 #include <signal.h>
0007 #include <sys/ioctl.h>
0008 #include "pager.h"
0009 #include "run-command.h"
0010 #include "sigchain.h"
0011 #include "subcmd-config.h"
0012 
0013 /*
0014  * This is split up from the rest of git so that we can do
0015  * something different on Windows.
0016  */
0017 
0018 static int spawned_pager;
0019 static int pager_columns;
0020 
0021 void pager_init(const char *pager_env)
0022 {
0023     subcmd_config.pager_env = pager_env;
0024 }
0025 
0026 static const char *forced_pager;
0027 
0028 void force_pager(const char *pager)
0029 {
0030     forced_pager = pager;
0031 }
0032 
0033 static void pager_preexec(void)
0034 {
0035     /*
0036      * Work around bug in "less" by not starting it until we
0037      * have real input
0038      */
0039     fd_set in;
0040     fd_set exception;
0041 
0042     FD_ZERO(&in);
0043     FD_ZERO(&exception);
0044     FD_SET(0, &in);
0045     FD_SET(0, &exception);
0046     select(1, &in, NULL, &exception, NULL);
0047 
0048     setenv("LESS", "FRSX", 0);
0049 }
0050 
0051 static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
0052 static struct child_process pager_process;
0053 
0054 static void wait_for_pager(void)
0055 {
0056     fflush(stdout);
0057     fflush(stderr);
0058     /* signal EOF to pager */
0059     close(1);
0060     close(2);
0061     finish_command(&pager_process);
0062 }
0063 
0064 static void wait_for_pager_signal(int signo)
0065 {
0066     wait_for_pager();
0067     sigchain_pop(signo);
0068     raise(signo);
0069 }
0070 
0071 void setup_pager(void)
0072 {
0073     const char *pager = getenv(subcmd_config.pager_env);
0074     struct winsize sz;
0075 
0076     if (forced_pager)
0077         pager = forced_pager;
0078     if (!isatty(1) && !forced_pager)
0079         return;
0080     if (ioctl(1, TIOCGWINSZ, &sz) == 0)
0081         pager_columns = sz.ws_col;
0082     if (!pager)
0083         pager = getenv("PAGER");
0084     if (!(pager || access("/usr/bin/pager", X_OK)))
0085         pager = "/usr/bin/pager";
0086     if (!(pager || access("/usr/bin/less", X_OK)))
0087         pager = "/usr/bin/less";
0088     if (!pager)
0089         pager = "cat";
0090     if (!*pager || !strcmp(pager, "cat"))
0091         return;
0092 
0093     spawned_pager = 1; /* means we are emitting to terminal */
0094 
0095     /* spawn the pager */
0096     pager_argv[2] = pager;
0097     pager_process.argv = pager_argv;
0098     pager_process.in = -1;
0099     pager_process.preexec_cb = pager_preexec;
0100 
0101     if (start_command(&pager_process))
0102         return;
0103 
0104     /* original process continues, but writes to the pipe */
0105     dup2(pager_process.in, 1);
0106     if (isatty(2))
0107         dup2(pager_process.in, 2);
0108     close(pager_process.in);
0109 
0110     /* this makes sure that the parent terminates after the pager */
0111     sigchain_push_common(wait_for_pager_signal);
0112     atexit(wait_for_pager);
0113 }
0114 
0115 int pager_in_use(void)
0116 {
0117     return spawned_pager;
0118 }
0119 
0120 int pager_get_columns(void)
0121 {
0122     char *s;
0123 
0124     s = getenv("COLUMNS");
0125     if (s)
0126         return atoi(s);
0127 
0128     return (pager_columns ? pager_columns : 80) - 2;
0129 }