2015-12-15 09:39:38 -06:00
# include <sys/select.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <signal.h>
2016-09-15 15:24:44 -07:00
# include <sys/ioctl.h>
2015-12-15 09:39:38 -06:00
# include "pager.h"
2009-05-27 09:50:13 +02:00
# include "run-command.h"
# include "sigchain.h"
2015-12-15 09:39:35 -06:00
# include "subcmd-config.h"
2009-05-27 09:50:13 +02:00
/*
* This is split up from the rest of git so that we can do
* something different on Windows .
*/
static int spawned_pager ;
2016-09-15 15:24:44 -07:00
static int pager_columns ;
2009-05-27 09:50:13 +02:00
2015-12-15 09:39:35 -06:00
void pager_init ( const char * pager_env )
{
subcmd_config . pager_env = pager_env ;
}
2009-05-27 09:50:13 +02:00
static void pager_preexec ( void )
{
/*
* Work around bug in " less " by not starting it until we
* have real input
*/
fd_set in ;
FD_ZERO ( & in ) ;
FD_SET ( 0 , & in ) ;
select ( 1 , & in , NULL , & in , NULL ) ;
setenv ( " LESS " , " FRSX " , 0 ) ;
}
static const char * pager_argv [ ] = { " sh " , " -c " , NULL , NULL } ;
static struct child_process pager_process ;
static void wait_for_pager ( void )
{
fflush ( stdout ) ;
fflush ( stderr ) ;
/* signal EOF to pager */
close ( 1 ) ;
close ( 2 ) ;
finish_command ( & pager_process ) ;
}
static void wait_for_pager_signal ( int signo )
{
wait_for_pager ( ) ;
sigchain_pop ( signo ) ;
raise ( signo ) ;
}
void setup_pager ( void )
{
2015-12-15 09:39:35 -06:00
const char * pager = getenv ( subcmd_config . pager_env ) ;
2016-09-15 15:24:44 -07:00
struct winsize sz ;
2009-05-27 09:50:13 +02:00
if ( ! isatty ( 1 ) )
return ;
2016-09-15 15:24:44 -07:00
if ( ioctl ( 1 , TIOCGWINSZ , & sz ) = = 0 )
pager_columns = sz . ws_col ;
2009-05-27 09:50:13 +02:00
if ( ! pager )
pager = getenv ( " PAGER " ) ;
2014-05-20 11:48:49 +02:00
if ( ! ( pager | | access ( " /usr/bin/pager " , X_OK ) ) )
pager = " /usr/bin/pager " ;
if ( ! ( pager | | access ( " /usr/bin/less " , X_OK ) ) )
pager = " /usr/bin/less " ;
2009-05-27 09:50:13 +02:00
if ( ! pager )
2014-05-20 11:48:49 +02:00
pager = " cat " ;
if ( ! * pager | | ! strcmp ( pager , " cat " ) )
2009-05-27 09:50:13 +02:00
return ;
spawned_pager = 1 ; /* means we are emitting to terminal */
/* spawn the pager */
pager_argv [ 2 ] = pager ;
pager_process . argv = pager_argv ;
pager_process . in = - 1 ;
pager_process . preexec_cb = pager_preexec ;
2009-06-27 06:06:39 +02:00
2009-05-27 09:50:13 +02:00
if ( start_command ( & pager_process ) )
return ;
/* original process continues, but writes to the pipe */
dup2 ( pager_process . in , 1 ) ;
if ( isatty ( 2 ) )
dup2 ( pager_process . in , 2 ) ;
close ( pager_process . in ) ;
/* this makes sure that the parent terminates after the pager */
sigchain_push_common ( wait_for_pager_signal ) ;
atexit ( wait_for_pager ) ;
}
int pager_in_use ( void )
{
2015-12-13 22:18:08 -06:00
return spawned_pager ;
2009-05-27 09:50:13 +02:00
}
2016-09-15 15:24:44 -07:00
int pager_get_columns ( void )
{
char * s ;
s = getenv ( " COLUMNS " ) ;
if ( s )
return atoi ( s ) ;
return ( pager_columns ? pager_columns : 80 ) - 2 ;
}