pager.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. #include <sys/select.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <signal.h>
  6. #include "pager.h"
  7. #include "run-command.h"
  8. #include "sigchain.h"
  9. #include "subcmd-config.h"
  10. /*
  11. * This is split up from the rest of git so that we can do
  12. * something different on Windows.
  13. */
  14. static int spawned_pager;
  15. void pager_init(const char *pager_env)
  16. {
  17. subcmd_config.pager_env = pager_env;
  18. }
  19. static void pager_preexec(void)
  20. {
  21. /*
  22. * Work around bug in "less" by not starting it until we
  23. * have real input
  24. */
  25. fd_set in;
  26. FD_ZERO(&in);
  27. FD_SET(0, &in);
  28. select(1, &in, NULL, &in, NULL);
  29. setenv("LESS", "FRSX", 0);
  30. }
  31. static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
  32. static struct child_process pager_process;
  33. static void wait_for_pager(void)
  34. {
  35. fflush(stdout);
  36. fflush(stderr);
  37. /* signal EOF to pager */
  38. close(1);
  39. close(2);
  40. finish_command(&pager_process);
  41. }
  42. static void wait_for_pager_signal(int signo)
  43. {
  44. wait_for_pager();
  45. sigchain_pop(signo);
  46. raise(signo);
  47. }
  48. void setup_pager(void)
  49. {
  50. const char *pager = getenv(subcmd_config.pager_env);
  51. if (!isatty(1))
  52. return;
  53. if (!pager)
  54. pager = getenv("PAGER");
  55. if (!(pager || access("/usr/bin/pager", X_OK)))
  56. pager = "/usr/bin/pager";
  57. if (!(pager || access("/usr/bin/less", X_OK)))
  58. pager = "/usr/bin/less";
  59. if (!pager)
  60. pager = "cat";
  61. if (!*pager || !strcmp(pager, "cat"))
  62. return;
  63. spawned_pager = 1; /* means we are emitting to terminal */
  64. /* spawn the pager */
  65. pager_argv[2] = pager;
  66. pager_process.argv = pager_argv;
  67. pager_process.in = -1;
  68. pager_process.preexec_cb = pager_preexec;
  69. if (start_command(&pager_process))
  70. return;
  71. /* original process continues, but writes to the pipe */
  72. dup2(pager_process.in, 1);
  73. if (isatty(2))
  74. dup2(pager_process.in, 2);
  75. close(pager_process.in);
  76. /* this makes sure that the parent terminates after the pager */
  77. sigchain_push_common(wait_for_pager_signal);
  78. atexit(wait_for_pager);
  79. }
  80. int pager_in_use(void)
  81. {
  82. return spawned_pager;
  83. }