2006-02-28 19:26:21 +00:00
|
|
|
#include "cache.h"
|
spawn pager via run_command interface
This has two important effects:
1. The pager is now the _child_ process, instead of the
parent. This means that whatever spawned git (e.g., the
shell) will see the exit code of the git process, and
not the pager.
2. The mingw and regular code are now unified, which makes
the setup_pager function much simpler.
There are two caveats:
1. We used to call execlp directly on the pager, followed
by trying to exec it via the shall. We now just use the
shell (which is what mingw has always done). This may
have different results for pager names which contain
shell metacharacters.
It is also slightly less efficient because we
unnecessarily run the shell; however, pager spawning is
by definition an interactive task, so it shouldn't be
a huge problem.
2. The git process will remain in memory while the user
looks through the pager. This is potentially wasteful.
We could get around this by turning the parent into a
meta-process which spawns _both_ git and the pager,
collects the exit status from git, waits for both to
end, and then exits with git's exit code.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-22 07:14:12 +00:00
|
|
|
#include "run-command.h"
|
pager: do wait_for_pager on signal death
Since ea27a18 (spawn pager via run_command interface), the
original git process actually does git work, and the pager
is a child process (actually, on Windows it has always been
that way, since Windows lacks fork). After spawning the
pager, we register an atexit() handler that waits for the
pager to finish.
Unfortunately, that handler does not always run. In
particular, if git is killed by a signal, then we exit
immediately. The calling shell then thinks that git is done;
however, the pager is still trying to run and impact the
terminal. The result can be seen by running a long git
process with a pager (e.g., "git log -p") and hitting ^C.
Depending on your config, you should see the shell prompt,
but pressing a key causes the pager to do any terminal
de-initialization sequence.
This patch just intercepts any death-dealing signals and
waits for the pager before dying. Under typical less
configuration, that means hitting ^C will cause git to stop
generating output, but the pager will keep running.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:03:28 +00:00
|
|
|
#include "sigchain.h"
|
2006-02-28 19:26:21 +00:00
|
|
|
|
2009-10-31 01:45:34 +00:00
|
|
|
#ifndef DEFAULT_PAGER
|
|
|
|
#define DEFAULT_PAGER "less"
|
|
|
|
#endif
|
|
|
|
|
2014-08-19 19:09:35 +00:00
|
|
|
static struct child_process pager_process = CHILD_PROCESS_INIT;
|
2016-09-13 03:23:48 +00:00
|
|
|
static const char *pager_program;
|
spawn pager via run_command interface
This has two important effects:
1. The pager is now the _child_ process, instead of the
parent. This means that whatever spawned git (e.g., the
shell) will see the exit code of the git process, and
not the pager.
2. The mingw and regular code are now unified, which makes
the setup_pager function much simpler.
There are two caveats:
1. We used to call execlp directly on the pager, followed
by trying to exec it via the shall. We now just use the
shell (which is what mingw has always done). This may
have different results for pager names which contain
shell metacharacters.
It is also slightly less efficient because we
unnecessarily run the shell; however, pager spawning is
by definition an interactive task, so it shouldn't be
a huge problem.
2. The git process will remain in memory while the user
looks through the pager. This is potentially wasteful.
We could get around this by turning the parent into a
meta-process which spawns _both_ git and the pager,
collects the exit status from git, waits for both to
end, and then exits with git's exit code.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-22 07:14:12 +00:00
|
|
|
|
pager: don't use unsafe functions in signal handlers
Since the commit a3da8821208d (pager: do wait_for_pager on signal
death), we call wait_for_pager() in the pager's signal handler. The
recent bug report revealed that this causes a deadlock in glibc at
aborting "git log" [*1*]. When this happens, git process is left
unterminated, and it can't be killed by SIGTERM but only by SIGKILL.
The problem is that wait_for_pager() function does more than waiting
for pager process's termination, but it does cleanups and printing
errors. Unfortunately, the functions that may be used in a signal
handler are very limited [*2*]. Particularly, malloc(), free() and the
variants can't be used in a signal handler because they take a mutex
internally in glibc. This was the cause of the deadlock above. Other
than the direct calls of malloc/free, many functions calling
malloc/free can't be used. strerror() is such one, either.
Also the usage of fflush() and printf() in a signal handler is bad,
although it seems working so far. In a safer side, we should avoid
them, too.
This patch tries to reduce the calls of such functions in signal
handlers. wait_for_signal() takes a flag and avoids the unsafe
calls. Also, finish_command_in_signal() is introduced for the
same reason. There the free() calls are removed, and only waits for
the children without whining at errors.
[*1*] https://bugzilla.opensuse.org/show_bug.cgi?id=942297
[*2*] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:35:57 +00:00
|
|
|
static void wait_for_pager(int in_signal)
|
2007-12-08 20:28:41 +00:00
|
|
|
{
|
pager: don't use unsafe functions in signal handlers
Since the commit a3da8821208d (pager: do wait_for_pager on signal
death), we call wait_for_pager() in the pager's signal handler. The
recent bug report revealed that this causes a deadlock in glibc at
aborting "git log" [*1*]. When this happens, git process is left
unterminated, and it can't be killed by SIGTERM but only by SIGKILL.
The problem is that wait_for_pager() function does more than waiting
for pager process's termination, but it does cleanups and printing
errors. Unfortunately, the functions that may be used in a signal
handler are very limited [*2*]. Particularly, malloc(), free() and the
variants can't be used in a signal handler because they take a mutex
internally in glibc. This was the cause of the deadlock above. Other
than the direct calls of malloc/free, many functions calling
malloc/free can't be used. strerror() is such one, either.
Also the usage of fflush() and printf() in a signal handler is bad,
although it seems working so far. In a safer side, we should avoid
them, too.
This patch tries to reduce the calls of such functions in signal
handlers. wait_for_signal() takes a flag and avoids the unsafe
calls. Also, finish_command_in_signal() is introduced for the
same reason. There the free() calls are removed, and only waits for
the children without whining at errors.
[*1*] https://bugzilla.opensuse.org/show_bug.cgi?id=942297
[*2*] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:35:57 +00:00
|
|
|
if (!in_signal) {
|
|
|
|
fflush(stdout);
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
2007-12-08 20:28:41 +00:00
|
|
|
/* signal EOF to pager */
|
|
|
|
close(1);
|
|
|
|
close(2);
|
pager: don't use unsafe functions in signal handlers
Since the commit a3da8821208d (pager: do wait_for_pager on signal
death), we call wait_for_pager() in the pager's signal handler. The
recent bug report revealed that this causes a deadlock in glibc at
aborting "git log" [*1*]. When this happens, git process is left
unterminated, and it can't be killed by SIGTERM but only by SIGKILL.
The problem is that wait_for_pager() function does more than waiting
for pager process's termination, but it does cleanups and printing
errors. Unfortunately, the functions that may be used in a signal
handler are very limited [*2*]. Particularly, malloc(), free() and the
variants can't be used in a signal handler because they take a mutex
internally in glibc. This was the cause of the deadlock above. Other
than the direct calls of malloc/free, many functions calling
malloc/free can't be used. strerror() is such one, either.
Also the usage of fflush() and printf() in a signal handler is bad,
although it seems working so far. In a safer side, we should avoid
them, too.
This patch tries to reduce the calls of such functions in signal
handlers. wait_for_signal() takes a flag and avoids the unsafe
calls. Also, finish_command_in_signal() is introduced for the
same reason. There the free() calls are removed, and only waits for
the children without whining at errors.
[*1*] https://bugzilla.opensuse.org/show_bug.cgi?id=942297
[*2*] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:35:57 +00:00
|
|
|
if (in_signal)
|
|
|
|
finish_command_in_signal(&pager_process);
|
|
|
|
else
|
|
|
|
finish_command(&pager_process);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wait_for_pager_atexit(void)
|
|
|
|
{
|
|
|
|
wait_for_pager(0);
|
2007-12-08 20:28:41 +00:00
|
|
|
}
|
2006-02-28 19:26:21 +00:00
|
|
|
|
pager: do wait_for_pager on signal death
Since ea27a18 (spawn pager via run_command interface), the
original git process actually does git work, and the pager
is a child process (actually, on Windows it has always been
that way, since Windows lacks fork). After spawning the
pager, we register an atexit() handler that waits for the
pager to finish.
Unfortunately, that handler does not always run. In
particular, if git is killed by a signal, then we exit
immediately. The calling shell then thinks that git is done;
however, the pager is still trying to run and impact the
terminal. The result can be seen by running a long git
process with a pager (e.g., "git log -p") and hitting ^C.
Depending on your config, you should see the shell prompt,
but pressing a key causes the pager to do any terminal
de-initialization sequence.
This patch just intercepts any death-dealing signals and
waits for the pager before dying. Under typical less
configuration, that means hitting ^C will cause git to stop
generating output, but the pager will keep running.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:03:28 +00:00
|
|
|
static void wait_for_pager_signal(int signo)
|
|
|
|
{
|
pager: don't use unsafe functions in signal handlers
Since the commit a3da8821208d (pager: do wait_for_pager on signal
death), we call wait_for_pager() in the pager's signal handler. The
recent bug report revealed that this causes a deadlock in glibc at
aborting "git log" [*1*]. When this happens, git process is left
unterminated, and it can't be killed by SIGTERM but only by SIGKILL.
The problem is that wait_for_pager() function does more than waiting
for pager process's termination, but it does cleanups and printing
errors. Unfortunately, the functions that may be used in a signal
handler are very limited [*2*]. Particularly, malloc(), free() and the
variants can't be used in a signal handler because they take a mutex
internally in glibc. This was the cause of the deadlock above. Other
than the direct calls of malloc/free, many functions calling
malloc/free can't be used. strerror() is such one, either.
Also the usage of fflush() and printf() in a signal handler is bad,
although it seems working so far. In a safer side, we should avoid
them, too.
This patch tries to reduce the calls of such functions in signal
handlers. wait_for_signal() takes a flag and avoids the unsafe
calls. Also, finish_command_in_signal() is introduced for the
same reason. There the free() calls are removed, and only waits for
the children without whining at errors.
[*1*] https://bugzilla.opensuse.org/show_bug.cgi?id=942297
[*2*] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:35:57 +00:00
|
|
|
wait_for_pager(1);
|
pager: do wait_for_pager on signal death
Since ea27a18 (spawn pager via run_command interface), the
original git process actually does git work, and the pager
is a child process (actually, on Windows it has always been
that way, since Windows lacks fork). After spawning the
pager, we register an atexit() handler that waits for the
pager to finish.
Unfortunately, that handler does not always run. In
particular, if git is killed by a signal, then we exit
immediately. The calling shell then thinks that git is done;
however, the pager is still trying to run and impact the
terminal. The result can be seen by running a long git
process with a pager (e.g., "git log -p") and hitting ^C.
Depending on your config, you should see the shell prompt,
but pressing a key causes the pager to do any terminal
de-initialization sequence.
This patch just intercepts any death-dealing signals and
waits for the pager before dying. Under typical less
configuration, that means hitting ^C will cause git to stop
generating output, but the pager will keep running.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:03:28 +00:00
|
|
|
sigchain_pop(signo);
|
|
|
|
raise(signo);
|
|
|
|
}
|
|
|
|
|
pager: stop loading git_default_config()
In git_pager(), we really only care about getting the value
of core.pager. But to do so, we use the git_default_config()
callback, which loads many other values. Ordinarily it
isn't a big deal to load this config an extra time, as it
simply overwrites the values from the previous run. But it's
a bad idea here, for two reasons:
1. The pager setup may be called very early in the
program, before we have found the git repository. As a
result, we may fail to read the correct repo-level
config file. This is a problem for core.pager, too,
but we should at least try to minimize the pollution to
other configured values.
2. Because we call setup_pager() from git.c, basically
every builtin command _may_ end up reading this config
and getting an implicit git_default_config() setup.
Which doesn't sound like a terrible thing, except that
we don't do it consistently; it triggers only when
stdout is a tty. So if a command forgets to load the
default config itself (but depends on it anyway), it
may appear to work, and then mysteriously fail when the
pager is not in use.
We can improve this by loading _just_ the core.pager config
from git_pager().
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-09-13 03:23:44 +00:00
|
|
|
static int core_pager_config(const char *var, const char *value, void *data)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "core.pager"))
|
|
|
|
return git_config_string(&pager_program, var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-14 11:59:59 +00:00
|
|
|
const char *git_pager(int stdout_is_tty)
|
2006-02-28 19:26:21 +00:00
|
|
|
{
|
2009-10-31 01:41:27 +00:00
|
|
|
const char *pager;
|
2006-02-28 19:26:21 +00:00
|
|
|
|
2010-02-14 11:59:59 +00:00
|
|
|
if (!stdout_is_tty)
|
2009-10-31 01:41:27 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pager = getenv("GIT_PAGER");
|
2007-08-07 04:08:43 +00:00
|
|
|
if (!pager) {
|
|
|
|
if (!pager_program)
|
2016-09-13 03:23:56 +00:00
|
|
|
read_early_config(core_pager_config, NULL);
|
2007-07-03 18:18:11 +00:00
|
|
|
pager = pager_program;
|
2007-08-07 04:08:43 +00:00
|
|
|
}
|
2006-07-31 13:27:00 +00:00
|
|
|
if (!pager)
|
|
|
|
pager = getenv("PAGER");
|
2006-04-16 02:44:25 +00:00
|
|
|
if (!pager)
|
2009-10-31 01:45:34 +00:00
|
|
|
pager = DEFAULT_PAGER;
|
pager: turn on "cat" optimization for DEFAULT_PAGER
If the user specifies a pager of "cat" (or the empty
string), whether it is in the environment or from config, we
automagically optimize it out to mean "no pager" and avoid
forking at all. We treat an empty pager variable similary.
However, we did not apply this optimization when
DEFAULT_PAGER was set to "cat" (or the empty string). There
is no reason to treat DEFAULT_PAGER any differently. The
optimization should not be user-visible (unless the user has
a bizarre "cat" in their PATH). And even if it is, we are
better off behaving consistently between the compile-time
default and the environment and config settings.
The stray "else" we are removing from this code was
introduced by 402461a (pager: do not fork a pager if PAGER
is set to empty., 2006-04-16). At that time, the line
directly above used:
if (!pager)
pager = "less";
as a fallback, meaning that it could not possibly trigger
the optimization. Later, a3d023d (Provide a build time
default-pager setting, 2009-10-30) turned that constant into
a build-time setting which could be anything, but didn't
loosen the "else" to let DEFAULT_PAGER use the optimization.
Noticed-by: Dale R. Worley <worley@alum.mit.edu>
Suggested-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-03 07:41:50 +00:00
|
|
|
if (!*pager || !strcmp(pager, "cat"))
|
2009-10-31 01:41:27 +00:00
|
|
|
pager = NULL;
|
|
|
|
|
|
|
|
return pager;
|
|
|
|
}
|
|
|
|
|
2016-08-04 11:40:25 +00:00
|
|
|
static void setup_pager_env(struct argv_array *env)
|
|
|
|
{
|
|
|
|
const char **argv;
|
|
|
|
int i;
|
|
|
|
char *pager_env = xstrdup(PAGER_ENV);
|
|
|
|
int n = split_cmdline(pager_env, &argv);
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
die("malformed build-time PAGER_ENV: %s",
|
|
|
|
split_cmdline_strerror(n));
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
char *cp = strchr(argv[i], '=');
|
|
|
|
|
|
|
|
if (!cp)
|
|
|
|
die("malformed build-time PAGER_ENV");
|
|
|
|
|
|
|
|
*cp = '\0';
|
|
|
|
if (!getenv(argv[i])) {
|
|
|
|
*cp = '=';
|
|
|
|
argv_array_push(env, argv[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(pager_env);
|
|
|
|
free(argv);
|
|
|
|
}
|
|
|
|
|
2016-02-16 22:34:44 +00:00
|
|
|
void prepare_pager_args(struct child_process *pager_process, const char *pager)
|
|
|
|
{
|
|
|
|
argv_array_push(&pager_process->args, pager);
|
|
|
|
pager_process->use_shell = 1;
|
2016-08-04 11:40:25 +00:00
|
|
|
setup_pager_env(&pager_process->env_array);
|
2016-02-16 22:34:44 +00:00
|
|
|
}
|
|
|
|
|
2009-10-31 01:41:27 +00:00
|
|
|
void setup_pager(void)
|
|
|
|
{
|
2010-02-14 11:59:59 +00:00
|
|
|
const char *pager = git_pager(isatty(1));
|
2009-10-31 01:41:27 +00:00
|
|
|
|
2014-04-21 20:46:22 +00:00
|
|
|
if (!pager)
|
2006-04-16 02:44:25 +00:00
|
|
|
return;
|
|
|
|
|
2012-02-12 14:12:32 +00:00
|
|
|
/*
|
|
|
|
* force computing the width of the terminal before we redirect
|
|
|
|
* the standard output to the pager.
|
|
|
|
*/
|
|
|
|
(void) term_columns();
|
|
|
|
|
2011-08-18 05:02:29 +00:00
|
|
|
setenv("GIT_PAGER_IN_USE", "true", 1);
|
2006-06-06 23:58:40 +00:00
|
|
|
|
2007-12-08 20:28:41 +00:00
|
|
|
/* spawn the pager */
|
2016-02-16 22:34:44 +00:00
|
|
|
prepare_pager_args(&pager_process, pager);
|
spawn pager via run_command interface
This has two important effects:
1. The pager is now the _child_ process, instead of the
parent. This means that whatever spawned git (e.g., the
shell) will see the exit code of the git process, and
not the pager.
2. The mingw and regular code are now unified, which makes
the setup_pager function much simpler.
There are two caveats:
1. We used to call execlp directly on the pager, followed
by trying to exec it via the shall. We now just use the
shell (which is what mingw has always done). This may
have different results for pager names which contain
shell metacharacters.
It is also slightly less efficient because we
unnecessarily run the shell; however, pager spawning is
by definition an interactive task, so it shouldn't be
a huge problem.
2. The git process will remain in memory while the user
looks through the pager. This is potentially wasteful.
We could get around this by turning the parent into a
meta-process which spawns _both_ git and the pager,
collects the exit status from git, waits for both to
end, and then exits with git's exit code.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-22 07:14:12 +00:00
|
|
|
pager_process.in = -1;
|
2015-07-03 17:18:45 +00:00
|
|
|
argv_array_push(&pager_process.env_array, "GIT_PAGER_IN_USE");
|
2007-12-08 20:28:41 +00:00
|
|
|
if (start_command(&pager_process))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* original process continues, but writes to the pipe */
|
|
|
|
dup2(pager_process.in, 1);
|
2008-12-15 08:33:34 +00:00
|
|
|
if (isatty(2))
|
|
|
|
dup2(pager_process.in, 2);
|
2007-12-08 20:28:41 +00:00
|
|
|
close(pager_process.in);
|
|
|
|
|
|
|
|
/* this makes sure that the parent terminates after the pager */
|
pager: do wait_for_pager on signal death
Since ea27a18 (spawn pager via run_command interface), the
original git process actually does git work, and the pager
is a child process (actually, on Windows it has always been
that way, since Windows lacks fork). After spawning the
pager, we register an atexit() handler that waits for the
pager to finish.
Unfortunately, that handler does not always run. In
particular, if git is killed by a signal, then we exit
immediately. The calling shell then thinks that git is done;
however, the pager is still trying to run and impact the
terminal. The result can be seen by running a long git
process with a pager (e.g., "git log -p") and hitting ^C.
Depending on your config, you should see the shell prompt,
but pressing a key causes the pager to do any terminal
de-initialization sequence.
This patch just intercepts any death-dealing signals and
waits for the pager before dying. Under typical less
configuration, that means hitting ^C will cause git to stop
generating output, but the pager will keep running.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-01-22 06:03:28 +00:00
|
|
|
sigchain_push_common(wait_for_pager_signal);
|
pager: don't use unsafe functions in signal handlers
Since the commit a3da8821208d (pager: do wait_for_pager on signal
death), we call wait_for_pager() in the pager's signal handler. The
recent bug report revealed that this causes a deadlock in glibc at
aborting "git log" [*1*]. When this happens, git process is left
unterminated, and it can't be killed by SIGTERM but only by SIGKILL.
The problem is that wait_for_pager() function does more than waiting
for pager process's termination, but it does cleanups and printing
errors. Unfortunately, the functions that may be used in a signal
handler are very limited [*2*]. Particularly, malloc(), free() and the
variants can't be used in a signal handler because they take a mutex
internally in glibc. This was the cause of the deadlock above. Other
than the direct calls of malloc/free, many functions calling
malloc/free can't be used. strerror() is such one, either.
Also the usage of fflush() and printf() in a signal handler is bad,
although it seems working so far. In a safer side, we should avoid
them, too.
This patch tries to reduce the calls of such functions in signal
handlers. wait_for_signal() takes a flag and avoids the unsafe
calls. Also, finish_command_in_signal() is introduced for the
same reason. There the free() calls are removed, and only waits for
the children without whining at errors.
[*1*] https://bugzilla.opensuse.org/show_bug.cgi?id=942297
[*2*] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-04 09:35:57 +00:00
|
|
|
atexit(wait_for_pager_atexit);
|
2006-02-28 19:26:21 +00:00
|
|
|
}
|
2007-12-11 06:27:33 +00:00
|
|
|
|
|
|
|
int pager_in_use(void)
|
|
|
|
{
|
|
|
|
const char *env;
|
|
|
|
env = getenv("GIT_PAGER_IN_USE");
|
|
|
|
return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
|
|
|
|
}
|
2012-02-12 14:12:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return cached value (if set) or $COLUMNS environment variable (if
|
|
|
|
* set and positive) or ioctl(1, TIOCGWINSZ).ws_col (if positive),
|
|
|
|
* and default to 80 if all else fails.
|
|
|
|
*/
|
|
|
|
int term_columns(void)
|
|
|
|
{
|
|
|
|
static int term_columns_at_startup;
|
|
|
|
|
|
|
|
char *col_string;
|
|
|
|
int n_cols;
|
|
|
|
|
|
|
|
if (term_columns_at_startup)
|
|
|
|
return term_columns_at_startup;
|
|
|
|
|
|
|
|
term_columns_at_startup = 80;
|
|
|
|
|
|
|
|
col_string = getenv("COLUMNS");
|
|
|
|
if (col_string && (n_cols = atoi(col_string)) > 0)
|
|
|
|
term_columns_at_startup = n_cols;
|
|
|
|
#ifdef TIOCGWINSZ
|
|
|
|
else {
|
|
|
|
struct winsize ws;
|
|
|
|
if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_col)
|
|
|
|
term_columns_at_startup = ws.ws_col;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return term_columns_at_startup;
|
|
|
|
}
|
2012-02-20 08:15:11 +00:00
|
|
|
|
2012-02-12 14:16:20 +00:00
|
|
|
/*
|
|
|
|
* How many columns do we need to show this number in decimal?
|
|
|
|
*/
|
decimal_width: avoid integer overflow
The decimal_width function originally appeared in blame.c as
"lineno_width", and was designed for calculating the
print-width of small-ish integer values (line numbers in
text files). In ec7ff5b, it was made into a reusable
function, and in dc801e7, we started using it to align
diffstats.
Binary files in a diffstat show byte counts rather than line
numbers, meaning they can be quite large (e.g., consider
adding or removing a 2GB file). decimal_width is not up to
the challenge for two reasons:
1. It takes the value as an "int", whereas large files may
easily surpass this. The value may be truncated, in
which case we will produce an incorrect value.
2. It counts "up" by repeatedly multiplying another
integer by 10 until it surpasses the value. This can
cause an infinite loop when the value is close to the
largest representable integer.
For example, consider using a 32-bit signed integer,
and a value of 2,140,000,000 (just shy of 2^31-1).
We will count up and eventually see that 1,000,000,000
is smaller than our value. The next step would be to
multiply by 10 and see that 10,000,000,000 is too
large, ending the loop. But we can't represent that
value, and we have signed overflow.
This is technically undefined behavior, but a common
behavior is to lose the high bits, in which case our
iterator will certainly be less than the number. So
we'll keep multiplying, overflow again, and so on.
This patch changes the argument to a uintmax_t (the same
type we use to store the diffstat information for binary
filese), and counts "down" by repeatedly dividing our value
by 10.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 08:14:19 +00:00
|
|
|
int decimal_width(uintmax_t number)
|
2012-02-12 14:16:20 +00:00
|
|
|
{
|
decimal_width: avoid integer overflow
The decimal_width function originally appeared in blame.c as
"lineno_width", and was designed for calculating the
print-width of small-ish integer values (line numbers in
text files). In ec7ff5b, it was made into a reusable
function, and in dc801e7, we started using it to align
diffstats.
Binary files in a diffstat show byte counts rather than line
numbers, meaning they can be quite large (e.g., consider
adding or removing a 2GB file). decimal_width is not up to
the challenge for two reasons:
1. It takes the value as an "int", whereas large files may
easily surpass this. The value may be truncated, in
which case we will produce an incorrect value.
2. It counts "up" by repeatedly multiplying another
integer by 10 until it surpasses the value. This can
cause an infinite loop when the value is close to the
largest representable integer.
For example, consider using a 32-bit signed integer,
and a value of 2,140,000,000 (just shy of 2^31-1).
We will count up and eventually see that 1,000,000,000
is smaller than our value. The next step would be to
multiply by 10 and see that 10,000,000,000 is too
large, ending the loop. But we can't represent that
value, and we have signed overflow.
This is technically undefined behavior, but a common
behavior is to lose the high bits, in which case our
iterator will certainly be less than the number. So
we'll keep multiplying, overflow again, and so on.
This patch changes the argument to a uintmax_t (the same
type we use to store the diffstat information for binary
filese), and counts "down" by repeatedly dividing our value
by 10.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 08:14:19 +00:00
|
|
|
int width;
|
2012-02-12 14:16:20 +00:00
|
|
|
|
decimal_width: avoid integer overflow
The decimal_width function originally appeared in blame.c as
"lineno_width", and was designed for calculating the
print-width of small-ish integer values (line numbers in
text files). In ec7ff5b, it was made into a reusable
function, and in dc801e7, we started using it to align
diffstats.
Binary files in a diffstat show byte counts rather than line
numbers, meaning they can be quite large (e.g., consider
adding or removing a 2GB file). decimal_width is not up to
the challenge for two reasons:
1. It takes the value as an "int", whereas large files may
easily surpass this. The value may be truncated, in
which case we will produce an incorrect value.
2. It counts "up" by repeatedly multiplying another
integer by 10 until it surpasses the value. This can
cause an infinite loop when the value is close to the
largest representable integer.
For example, consider using a 32-bit signed integer,
and a value of 2,140,000,000 (just shy of 2^31-1).
We will count up and eventually see that 1,000,000,000
is smaller than our value. The next step would be to
multiply by 10 and see that 10,000,000,000 is too
large, ending the loop. But we can't represent that
value, and we have signed overflow.
This is technically undefined behavior, but a common
behavior is to lose the high bits, in which case our
iterator will certainly be less than the number. So
we'll keep multiplying, overflow again, and so on.
This patch changes the argument to a uintmax_t (the same
type we use to store the diffstat information for binary
filese), and counts "down" by repeatedly dividing our value
by 10.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-02-05 08:14:19 +00:00
|
|
|
for (width = 1; number >= 10; width++)
|
|
|
|
number /= 10;
|
2012-02-12 14:16:20 +00:00
|
|
|
return width;
|
|
|
|
}
|
2012-10-26 15:53:52 +00:00
|
|
|
|
2016-09-13 03:23:52 +00:00
|
|
|
struct pager_command_config_data {
|
|
|
|
const char *cmd;
|
|
|
|
int want;
|
|
|
|
char *value;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int pager_command_config(const char *var, const char *value, void *vdata)
|
2012-10-26 15:53:52 +00:00
|
|
|
{
|
2016-09-13 03:23:52 +00:00
|
|
|
struct pager_command_config_data *data = vdata;
|
|
|
|
const char *cmd;
|
|
|
|
|
|
|
|
if (skip_prefix(var, "pager.", &cmd) && !strcmp(cmd, data->cmd)) {
|
|
|
|
int b = git_config_maybe_bool(var, value);
|
2012-10-26 15:53:52 +00:00
|
|
|
if (b >= 0)
|
2016-09-13 03:23:52 +00:00
|
|
|
data->want = b;
|
2012-10-26 15:53:52 +00:00
|
|
|
else {
|
2016-09-13 03:23:52 +00:00
|
|
|
data->want = 1;
|
|
|
|
data->value = xstrdup(value);
|
2012-10-26 15:53:52 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-13 03:23:52 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
|
|
|
|
int check_pager_config(const char *cmd)
|
|
|
|
{
|
|
|
|
struct pager_command_config_data data;
|
|
|
|
|
|
|
|
data.cmd = cmd;
|
|
|
|
data.want = -1;
|
|
|
|
data.value = NULL;
|
|
|
|
|
2016-09-13 03:23:56 +00:00
|
|
|
read_early_config(pager_command_config, &data);
|
2016-09-13 03:23:52 +00:00
|
|
|
|
|
|
|
if (data.value)
|
|
|
|
pager_program = data.value;
|
|
|
|
return data.want;
|
2012-10-26 15:53:52 +00:00
|
|
|
}
|