1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include "libbb.h"
39#include "common_bufsiz.h"
40
41struct globals {
42 int tty_fileno;
43 unsigned terminal_width;
44 unsigned terminal_height;
45 struct termios initial_settings;
46} FIX_ALIASING;
47#define G (*(struct globals*)bb_common_bufsiz1)
48#define INIT_G() do { setup_common_bufsiz(); } while (0)
49
50static void get_wh(void)
51{
52
53 get_terminal_width_height(G.tty_fileno, &G.terminal_width, &G.terminal_height);
54 G.terminal_height -= 1;
55}
56
57static void tcsetattr_tty_TCSANOW(struct termios *settings)
58{
59 tcsetattr(G.tty_fileno, TCSANOW, settings);
60}
61
62static void gotsig(int sig UNUSED_PARAM)
63{
64
65
66 bb_putchar_stderr('\n');
67 tcsetattr_tty_TCSANOW(&G.initial_settings);
68 _exit(EXIT_FAILURE);
69}
70
71#define CONVERTED_TAB_SIZE 8
72
73int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
74int more_main(int argc UNUSED_PARAM, char **argv)
75{
76 int c = c;
77 int input = 0;
78 int spaces = 0;
79 int please_display_more_prompt;
80 FILE *tty;
81
82 INIT_G();
83
84
85
86
87
88
89
90
91
92 getopt32(argv, "deflsu");
93 argv += optind;
94
95
96
97 if (!isatty(STDOUT_FILENO))
98 return bb_cat(argv);
99 tty = fopen_for_read(CURRENT_TTY);
100 if (!tty)
101 return bb_cat(argv);
102
103 G.tty_fileno = fileno(tty);
104
105
106 set_termios_to_raw(G.tty_fileno, &G.initial_settings, 0);
107 bb_signals(BB_FATAL_SIGS, gotsig);
108
109 do {
110 struct stat st;
111 FILE *file;
112 int len;
113 int lines;
114
115 file = stdin;
116 if (*argv) {
117 file = fopen_or_warn(*argv, "r");
118 if (!file)
119 continue;
120 }
121 st.st_size = 0;
122 fstat(fileno(file), &st);
123
124 get_wh();
125
126 please_display_more_prompt = 0;
127 len = 0;
128 lines = 0;
129 for (;;) {
130 int wrap;
131
132 if (spaces)
133 spaces--;
134 else {
135 c = getc(file);
136 if (c == EOF) break;
137 }
138 loop_top:
139 if (input != 'r' && please_display_more_prompt) {
140 len = printf("--More-- ");
141 if (st.st_size != 0) {
142 uoff_t d = (uoff_t)st.st_size / 100;
143 if (d == 0)
144 d = 1;
145 len += printf("(%u%% of %"OFF_FMT"u bytes)",
146 (int) ((uoff_t)ftello(file) / d),
147 st.st_size);
148 }
149
150
151
152
153
154 for (;;) {
155 fflush_all();
156 input = getc(tty);
157 input = tolower(input);
158
159 printf("\r%*s\r", len, "");
160
161 if (input == 'q')
162 goto end;
163
164
165
166
167
168 if (input == ' ' || input == '\n' || input == 'r')
169 break;
170 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
171 }
172 len = 0;
173 lines = 0;
174 please_display_more_prompt = 0;
175
176
177
178 get_wh();
179 }
180
181
182
183 if (c == '\t') {
184 spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE;
185 c = ' ';
186 }
187
188
189
190
191
192
193
194
195
196
197
198 wrap = (++len > G.terminal_width);
199 if (c == '\n' || wrap) {
200
201
202 if (++lines >= G.terminal_height || input == '\n')
203 please_display_more_prompt = 1;
204 len = 0;
205 }
206 if (c != '\n' && wrap) {
207
208
209
210
211
212 goto loop_top;
213 }
214
215 putchar(c);
216 die_if_ferror_stdout();
217 }
218 fclose(file);
219 fflush_all();
220 } while (*argv && *++argv);
221 end:
222 tcsetattr_tty_TCSANOW(&G.initial_settings);
223 return 0;
224}
225