1 /* vi: set sw=4 ts=4: */
3 * Mini more implementation for busybox
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
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.
12 * Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
14 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
19 /* Support for FEATURE_USE_TERMIOS */
23 struct termios initial_settings
;
24 struct termios new_settings
;
26 #define G (*(struct globals*)bb_common_bufsiz1)
27 #define INIT_G() ((void)0)
28 #define initial_settings (G.initial_settings)
29 #define new_settings (G.new_settings )
30 #define cin_fileno (G.cin_fileno )
32 #define setTermSettings(fd, argp) \
34 if (ENABLE_FEATURE_USE_TERMIOS) \
35 tcsetattr(fd, TCSANOW, argp); \
37 #define getTermSettings(fd, argp) tcgetattr(fd, argp)
39 static void gotsig(int sig UNUSED_PARAM
)
41 /* bb_putchar_stderr doesn't use stdio buffering,
42 * therefore it is safe in signal handler */
43 bb_putchar_stderr('\n');
44 setTermSettings(cin_fileno
, &initial_settings
);
48 #define CONVERTED_TAB_SIZE 8
50 int more_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
51 int more_main(int argc UNUSED_PARAM
, char **argv
)
53 int c
= c
; /* for compiler */
57 int please_display_more_prompt
;
62 unsigned terminal_width
;
63 unsigned terminal_height
;
68 /* Another popular pager, most, detects when stdout
69 * is not a tty and turns into cat. This makes sense. */
70 if (!isatty(STDOUT_FILENO
))
72 cin
= fopen_for_read(CURRENT_TTY
);
76 if (ENABLE_FEATURE_USE_TERMIOS
) {
77 cin_fileno
= fileno(cin
);
78 getTermSettings(cin_fileno
, &initial_settings
);
79 new_settings
= initial_settings
;
80 new_settings
.c_lflag
&= ~ICANON
;
81 new_settings
.c_lflag
&= ~ECHO
;
82 new_settings
.c_cc
[VMIN
] = 1;
83 new_settings
.c_cc
[VTIME
] = 0;
84 setTermSettings(cin_fileno
, &new_settings
);
95 file
= fopen_or_warn(*argv
, "r");
100 fstat(fileno(file
), &st
);
102 please_display_more_prompt
= 0;
103 /* never returns w, h <= 1 */
104 get_terminal_width_height(fileno(cin
), &terminal_width
, &terminal_height
);
105 terminal_height
-= 1;
109 while (spaces
|| (c
= getc(file
)) != EOF
) {
114 if (input
!= 'r' && please_display_more_prompt
) {
115 len
= printf("--More-- ");
116 if (st
.st_size
!= 0) {
117 uoff_t d
= (uoff_t
)st
.st_size
/ 100;
120 len
+= printf("(%u%% of %"OFF_FMT
"u bytes)",
121 (int) ((uoff_t
)ftello(file
) / d
),
127 * We've just displayed the "--More--" prompt, so now we need
128 * to get input from the user.
132 input
= tolower(input
);
133 if (!ENABLE_FEATURE_USE_TERMIOS
)
134 printf("\033[A"); /* cursor up */
135 /* Erase the last message */
136 printf("\r%*s\r", len
, "");
138 /* Due to various multibyte escape
139 * sequences, it's not ok to accept
140 * any input as a command to scroll
141 * the screen. We only allow known
142 * commands, else we show help msg. */
143 if (input
== ' ' || input
== '\n' || input
== 'q' || input
== 'r')
145 len
= printf("(Enter:next line Space:next page Q:quit R:show the rest)");
149 please_display_more_prompt
= 0;
154 /* The user may have resized the terminal.
155 * Re-read the dimensions. */
156 if (ENABLE_FEATURE_USE_TERMIOS
) {
157 get_terminal_width_height(cin_fileno
, &terminal_width
, &terminal_height
);
158 terminal_height
-= 1;
162 /* Crudely convert tabs into spaces, which are
163 * a bajillion times easier to deal with. */
165 spaces
= ((unsigned)~len
) % CONVERTED_TAB_SIZE
;
170 * There are two input streams to worry about here:
172 * c : the character we are reading from the file being "mored"
173 * input: a character received from the keyboard
175 * If we hit a newline in the _file_ stream, we want to test and
176 * see if any characters have been hit in the _input_ stream. This
177 * allows the user to quit while in the middle of a file.
179 wrap
= (++len
> terminal_width
);
180 if (c
== '\n' || wrap
) {
181 /* Then outputting this character
182 * will move us to a new line. */
183 if (++lines
>= terminal_height
|| input
== '\n')
184 please_display_more_prompt
= 1;
187 if (c
!= '\n' && wrap
) {
188 /* Then outputting this will also put a character on
189 * the beginning of that new line. Thus we first want to
190 * display the prompt (if any), so we skip the putchar()
191 * and go back to the top of the loop, without reading
192 * a new character. */
195 /* My small mind cannot fathom backspaces and UTF-8 */
200 } while (*argv
&& *++argv
);
202 setTermSettings(cin_fileno
, &initial_settings
);