root/tools/lib/subcmd/pager.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pager_init
  2. force_pager
  3. pager_preexec
  4. wait_for_pager
  5. wait_for_pager_signal
  6. setup_pager
  7. pager_in_use
  8. pager_get_columns

   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 
  18 static int spawned_pager;
  19 static int pager_columns;
  20 
  21 void pager_init(const char *pager_env)
  22 {
  23         subcmd_config.pager_env = pager_env;
  24 }
  25 
  26 static const char *forced_pager;
  27 
  28 void force_pager(const char *pager)
  29 {
  30         forced_pager = pager;
  31 }
  32 
  33 static void pager_preexec(void)
  34 {
  35         /*
  36          * Work around bug in "less" by not starting it until we
  37          * have real input
  38          */
  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 
  51 static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
  52 static struct child_process pager_process;
  53 
  54 static 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 
  64 static void wait_for_pager_signal(int signo)
  65 {
  66         wait_for_pager();
  67         sigchain_pop(signo);
  68         raise(signo);
  69 }
  70 
  71 void 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 
 115 int pager_in_use(void)
 116 {
 117         return spawned_pager;
 118 }
 119 
 120 int 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 }

/* [<][>][^][v][top][bottom][index][help] */