1#include"cache.h" 2#include"run-command.h" 3#include"sigchain.h" 4 5#ifndef DEFAULT_PAGER 6#define DEFAULT_PAGER"less" 7#endif 8 9static struct child_process pager_process = CHILD_PROCESS_INIT; 10static const char*pager_program; 11 12static voidwait_for_pager(int in_signal) 13{ 14if(!in_signal) { 15fflush(stdout); 16fflush(stderr); 17} 18/* signal EOF to pager */ 19close(1); 20close(2); 21if(in_signal) 22finish_command_in_signal(&pager_process); 23else 24finish_command(&pager_process); 25} 26 27static voidwait_for_pager_atexit(void) 28{ 29wait_for_pager(0); 30} 31 32static voidwait_for_pager_signal(int signo) 33{ 34wait_for_pager(1); 35sigchain_pop(signo); 36raise(signo); 37} 38 39static intcore_pager_config(const char*var,const char*value,void*data) 40{ 41if(!strcmp(var,"core.pager")) 42returngit_config_string(&pager_program, var, value); 43return0; 44} 45 46static voidread_early_config(config_fn_t cb,void*data) 47{ 48git_config_with_options(cb, data, NULL,1); 49 50/* 51 * Note that this is a really dirty hack that does the wrong thing in 52 * many cases. The crux of the problem is that we cannot run 53 * setup_git_directory() early on in git's setup, so we have no idea if 54 * we are in a repository or not, and therefore are not sure whether 55 * and how to read repository-local config. 56 * 57 * So if we _aren't_ in a repository (or we are but we would reject its 58 * core.repositoryformatversion), we'll read whatever is in .git/config 59 * blindly. Similarly, if we _are_ in a repository, but not at the 60 * root, we'll fail to find .git/config (because it's really 61 * ../.git/config, etc). See t7006 for a complete set of failures. 62 * 63 * However, we have historically provided this hack because it does 64 * work some of the time (namely when you are at the top-level of a 65 * valid repository), and would rarely make things worse (i.e., you do 66 * not generally have a .git/config file sitting around). 67 */ 68if(!startup_info->have_repository) { 69struct git_config_source repo_config; 70 71memset(&repo_config,0,sizeof(repo_config)); 72 repo_config.file =".git/config"; 73git_config_with_options(cb, data, &repo_config,1); 74} 75} 76 77const char*git_pager(int stdout_is_tty) 78{ 79const char*pager; 80 81if(!stdout_is_tty) 82return NULL; 83 84 pager =getenv("GIT_PAGER"); 85if(!pager) { 86if(!pager_program) 87read_early_config(core_pager_config, NULL); 88 pager = pager_program; 89} 90if(!pager) 91 pager =getenv("PAGER"); 92if(!pager) 93 pager = DEFAULT_PAGER; 94if(!*pager || !strcmp(pager,"cat")) 95 pager = NULL; 96 97return pager; 98} 99 100voidprepare_pager_args(struct child_process *pager_process,const char*pager) 101{ 102argv_array_push(&pager_process->args, pager); 103 pager_process->use_shell =1; 104if(!getenv("LESS")) 105argv_array_push(&pager_process->env_array,"LESS=FRX"); 106if(!getenv("LV")) 107argv_array_push(&pager_process->env_array,"LV=-c"); 108} 109 110voidsetup_pager(void) 111{ 112const char*pager =git_pager(isatty(1)); 113 114if(!pager) 115return; 116 117/* 118 * force computing the width of the terminal before we redirect 119 * the standard output to the pager. 120 */ 121(void)term_columns(); 122 123setenv("GIT_PAGER_IN_USE","true",1); 124 125/* spawn the pager */ 126prepare_pager_args(&pager_process, pager); 127 pager_process.in = -1; 128argv_array_push(&pager_process.env_array,"GIT_PAGER_IN_USE"); 129if(start_command(&pager_process)) 130return; 131 132/* original process continues, but writes to the pipe */ 133dup2(pager_process.in,1); 134if(isatty(2)) 135dup2(pager_process.in,2); 136close(pager_process.in); 137 138/* this makes sure that the parent terminates after the pager */ 139sigchain_push_common(wait_for_pager_signal); 140atexit(wait_for_pager_atexit); 141} 142 143intpager_in_use(void) 144{ 145const char*env; 146 env =getenv("GIT_PAGER_IN_USE"); 147return env ?git_config_bool("GIT_PAGER_IN_USE", env) :0; 148} 149 150/* 151 * Return cached value (if set) or $COLUMNS environment variable (if 152 * set and positive) or ioctl(1, TIOCGWINSZ).ws_col (if positive), 153 * and default to 80 if all else fails. 154 */ 155intterm_columns(void) 156{ 157static int term_columns_at_startup; 158 159char*col_string; 160int n_cols; 161 162if(term_columns_at_startup) 163return term_columns_at_startup; 164 165 term_columns_at_startup =80; 166 167 col_string =getenv("COLUMNS"); 168if(col_string && (n_cols =atoi(col_string)) >0) 169 term_columns_at_startup = n_cols; 170#ifdef TIOCGWINSZ 171else{ 172struct winsize ws; 173if(!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_col) 174 term_columns_at_startup = ws.ws_col; 175} 176#endif 177 178return term_columns_at_startup; 179} 180 181/* 182 * How many columns do we need to show this number in decimal? 183 */ 184intdecimal_width(uintmax_t number) 185{ 186int width; 187 188for(width =1; number >=10; width++) 189 number /=10; 190return width; 191} 192 193struct pager_command_config_data { 194const char*cmd; 195int want; 196char*value; 197}; 198 199static intpager_command_config(const char*var,const char*value,void*vdata) 200{ 201struct pager_command_config_data *data = vdata; 202const char*cmd; 203 204if(skip_prefix(var,"pager.", &cmd) && !strcmp(cmd, data->cmd)) { 205int b =git_config_maybe_bool(var, value); 206if(b >=0) 207 data->want = b; 208else{ 209 data->want =1; 210 data->value =xstrdup(value); 211} 212} 213 214return0; 215} 216 217/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ 218intcheck_pager_config(const char*cmd) 219{ 220struct pager_command_config_data data; 221 222 data.cmd = cmd; 223 data.want = -1; 224 data.value = NULL; 225 226read_early_config(pager_command_config, &data); 227 228if(data.value) 229 pager_program = data.value; 230return data.want; 231}