1#include "cache.h"2#include "run-command.h"3#include "sigchain.h"45#ifndef DEFAULT_PAGER6#define DEFAULT_PAGER "less"7#endif89/*10* This is split up from the rest of git so that we can do11* something different on Windows.12*/1314#ifndef WIN3215static void pager_preexec(void)16{17/*18* Work around bug in "less" by not starting it until we19* have real input20*/21fd_set in;2223FD_ZERO(&in);24FD_SET(0, &in);25select(1, &in, NULL, &in, NULL);26}27#endif2829static const char *pager_argv[] = { NULL, NULL };30static struct child_process pager_process;3132static void wait_for_pager(void)33{34fflush(stdout);35fflush(stderr);36/* signal EOF to pager */37close(1);38close(2);39finish_command(&pager_process);40}4142static void wait_for_pager_signal(int signo)43{44wait_for_pager();45sigchain_pop(signo);46raise(signo);47}4849const char *git_pager(int stdout_is_tty)50{51const char *pager;5253if (!stdout_is_tty)54return NULL;5556pager = getenv("GIT_PAGER");57if (!pager) {58if (!pager_program)59git_config(git_default_config, NULL);60pager = pager_program;61}62if (!pager)63pager = getenv("PAGER");64if (!pager)65pager = DEFAULT_PAGER;66else if (!*pager || !strcmp(pager, "cat"))67pager = NULL;6869return pager;70}7172void setup_pager(void)73{74const char *pager = git_pager(isatty(1));7576if (!pager)77return;7879/*80* force computing the width of the terminal before we redirect81* the standard output to the pager.82*/83(void) term_columns();8485setenv("GIT_PAGER_IN_USE", "true", 1);8687/* spawn the pager */88pager_argv[0] = pager;89pager_process.use_shell = 1;90pager_process.argv = pager_argv;91pager_process.in = -1;92if (!getenv("LESS")) {93static const char *env[] = { "LESS=FRSX", NULL };94pager_process.env = env;95}96#ifndef WIN3297pager_process.preexec_cb = pager_preexec;98#endif99if (start_command(&pager_process))100return;101102/* original process continues, but writes to the pipe */103dup2(pager_process.in, 1);104if (isatty(2))105dup2(pager_process.in, 2);106close(pager_process.in);107108/* this makes sure that the parent terminates after the pager */109sigchain_push_common(wait_for_pager_signal);110atexit(wait_for_pager);111}112113int pager_in_use(void)114{115const char *env;116env = getenv("GIT_PAGER_IN_USE");117return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;118}119120/*121* Return cached value (if set) or $COLUMNS environment variable (if122* set and positive) or ioctl(1, TIOCGWINSZ).ws_col (if positive),123* and default to 80 if all else fails.124*/125int term_columns(void)126{127static int term_columns_at_startup;128129char *col_string;130int n_cols;131132if (term_columns_at_startup)133return term_columns_at_startup;134135term_columns_at_startup = 80;136137col_string = getenv("COLUMNS");138if (col_string && (n_cols = atoi(col_string)) > 0)139term_columns_at_startup = n_cols;140#ifdef TIOCGWINSZ141else {142struct winsize ws;143if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_col)144term_columns_at_startup = ws.ws_col;145}146#endif147148return term_columns_at_startup;149}150151/*152* How many columns do we need to show this number in decimal?153*/154int decimal_width(int number)155{156int i, width;157158for (width = 1, i = 10; i <= number; width++)159i *= 10;160return width;161}