more.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini more implementation for busybox
  4. *
  5. * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
  6. * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  7. *
  8. * Latest version blended together by Erik Andersen <andersen@codepoet.org>,
  9. * based on the original more implementation by Bruce, and code from the
  10. * Debian boot-floppies team.
  11. *
  12. * Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License as published by
  16. * the Free Software Foundation; either version 2 of the License, or
  17. * (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. *
  28. */
  29. #include <stdio.h>
  30. #include <fcntl.h>
  31. #include <signal.h>
  32. #include <stdlib.h>
  33. #include <unistd.h>
  34. #include <sys/ioctl.h>
  35. #include "busybox.h"
  36. #ifdef CONFIG_FEATURE_USE_TERMIOS
  37. static int cin_fileno;
  38. #include <termios.h>
  39. #define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
  40. #define getTermSettings(fd,argp) tcgetattr(fd, argp);
  41. static struct termios initial_settings, new_settings;
  42. static void set_tty_to_initial_mode(void)
  43. {
  44. setTermSettings(cin_fileno, &initial_settings);
  45. }
  46. static void gotsig(int sig)
  47. {
  48. putchar('\n');
  49. exit(EXIT_FAILURE);
  50. }
  51. #endif /* CONFIG_FEATURE_USE_TERMIOS */
  52. int more_main(int argc, char **argv)
  53. {
  54. int c, lines, input = 0;
  55. int please_display_more_prompt = 0;
  56. struct stat st;
  57. FILE *file;
  58. FILE *cin;
  59. int len, page_height;
  60. int terminal_width;
  61. int terminal_height;
  62. #ifndef CONFIG_FEATURE_USE_TERMIOS
  63. int cin_fileno;
  64. #endif
  65. argc--;
  66. argv++;
  67. /* not use inputing from terminal if usage: more > outfile */
  68. if(isatty(STDOUT_FILENO)) {
  69. cin = fopen(CURRENT_TTY, "r");
  70. if (!cin)
  71. cin = bb_xfopen(CONSOLE_DEV, "r");
  72. cin_fileno = fileno(cin);
  73. please_display_more_prompt = 2;
  74. #ifdef CONFIG_FEATURE_USE_TERMIOS
  75. getTermSettings(cin_fileno, &initial_settings);
  76. new_settings = initial_settings;
  77. new_settings.c_lflag &= ~ICANON;
  78. new_settings.c_lflag &= ~ECHO;
  79. new_settings.c_cc[VMIN] = 1;
  80. new_settings.c_cc[VTIME] = 0;
  81. setTermSettings(cin_fileno, &new_settings);
  82. atexit(set_tty_to_initial_mode);
  83. (void) signal(SIGINT, gotsig);
  84. (void) signal(SIGQUIT, gotsig);
  85. (void) signal(SIGTERM, gotsig);
  86. #endif
  87. } else {
  88. cin = stdin;
  89. }
  90. do {
  91. if (argc == 0) {
  92. file = stdin;
  93. } else
  94. file = bb_wfopen(*argv, "r");
  95. if(file==0)
  96. goto loop;
  97. st.st_size = 0;
  98. fstat(fileno(file), &st);
  99. please_display_more_prompt &= ~1;
  100. get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height);
  101. if (terminal_height > 4)
  102. terminal_height -= 2;
  103. if (terminal_width > 0)
  104. terminal_width -= 1;
  105. len=0;
  106. lines = 0;
  107. page_height = terminal_height;
  108. while ((c = getc(file)) != EOF) {
  109. if ((please_display_more_prompt & 3) == 3) {
  110. len = printf("--More-- ");
  111. if (file != stdin && st.st_size > 0) {
  112. #if _FILE_OFFSET_BITS == 64
  113. len += printf("(%d%% of %lld bytes)",
  114. (int) (100 * ((double) ftell(file) /
  115. (double) st.st_size)), (long long)st.st_size);
  116. #else
  117. len += printf("(%d%% of %ld bytes)",
  118. (int) (100 * ((double) ftell(file) /
  119. (double) st.st_size)), (long)st.st_size);
  120. #endif
  121. }
  122. fflush(stdout);
  123. /*
  124. * We've just displayed the "--More--" prompt, so now we need
  125. * to get input from the user.
  126. */
  127. input = getc(cin);
  128. #ifndef CONFIG_FEATURE_USE_TERMIOS
  129. printf("\033[A"); /* up cursor */
  130. #endif
  131. /* Erase the "More" message */
  132. putc('\r', stdout);
  133. while (--len >= 0)
  134. putc(' ', stdout);
  135. putc('\r', stdout);
  136. len=0;
  137. lines = 0;
  138. page_height = terminal_height;
  139. please_display_more_prompt &= ~1;
  140. if (input == 'q')
  141. goto end;
  142. }
  143. /*
  144. * There are two input streams to worry about here:
  145. *
  146. * c : the character we are reading from the file being "mored"
  147. * input : a character received from the keyboard
  148. *
  149. * If we hit a newline in the _file_ stream, we want to test and
  150. * see if any characters have been hit in the _input_ stream. This
  151. * allows the user to quit while in the middle of a file.
  152. */
  153. if (c == '\n') {
  154. /* increment by just one line if we are at
  155. * the end of this line */
  156. if (input == '\n')
  157. please_display_more_prompt |= 1;
  158. /* Adjust the terminal height for any overlap, so that
  159. * no lines get lost off the top. */
  160. if (len >= terminal_width) {
  161. int quot, rem;
  162. quot = len / terminal_width;
  163. rem = len - (quot * terminal_width);
  164. if (quot) {
  165. if (rem)
  166. page_height-=quot;
  167. else
  168. page_height-=(quot-1);
  169. }
  170. }
  171. if (++lines >= page_height) {
  172. please_display_more_prompt |= 1;
  173. }
  174. len=0;
  175. }
  176. /*
  177. * If we just read a newline from the file being 'mored' and any
  178. * key other than a return is hit, scroll by one page
  179. */
  180. putc(c, stdout);
  181. len++;
  182. }
  183. fclose(file);
  184. fflush(stdout);
  185. loop:
  186. argv++;
  187. } while (--argc > 0);
  188. end:
  189. return 0;
  190. }