source: MondoRescue/branches/3.3/mindi-busybox/util-linux/more.c@ 3625

Last change on this file since 3625 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 5.7 KB
Line 
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 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
15 */
16
17//usage:#define more_trivial_usage
18//usage: "[FILE]..."
19//usage:#define more_full_usage "\n\n"
20//usage: "View FILE (or stdin) one screenful at a time"
21//usage:
22//usage:#define more_example_usage
23//usage: "$ dmesg | more\n"
24
25#include "libbb.h"
26#include "common_bufsiz.h"
27
28/* Support for FEATURE_USE_TERMIOS */
29
30struct globals {
31 int cin_fileno;
32 struct termios initial_settings;
33 struct termios new_settings;
34} FIX_ALIASING;
35#define G (*(struct globals*)bb_common_bufsiz1)
36#define initial_settings (G.initial_settings)
37#define new_settings (G.new_settings )
38#define cin_fileno (G.cin_fileno )
39#define INIT_G() do { setup_common_bufsiz(); } while (0)
40
41#define setTermSettings(fd, argp) \
42do { \
43 if (ENABLE_FEATURE_USE_TERMIOS) \
44 tcsetattr(fd, TCSANOW, argp); \
45} while (0)
46#define getTermSettings(fd, argp) tcgetattr(fd, argp)
47
48static void gotsig(int sig UNUSED_PARAM)
49{
50 /* bb_putchar_stderr doesn't use stdio buffering,
51 * therefore it is safe in signal handler */
52 bb_putchar_stderr('\n');
53 setTermSettings(cin_fileno, &initial_settings);
54 _exit(EXIT_FAILURE);
55}
56
57#define CONVERTED_TAB_SIZE 8
58
59int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
60int more_main(int argc UNUSED_PARAM, char **argv)
61{
62 int c = c; /* for compiler */
63 int lines;
64 int input = 0;
65 int spaces = 0;
66 int please_display_more_prompt;
67 struct stat st;
68 FILE *file;
69 FILE *cin;
70 int len;
71 unsigned terminal_width;
72 unsigned terminal_height;
73
74 INIT_G();
75
76 argv++;
77 /* Another popular pager, most, detects when stdout
78 * is not a tty and turns into cat. This makes sense. */
79 if (!isatty(STDOUT_FILENO))
80 return bb_cat(argv);
81 cin = fopen_for_read(CURRENT_TTY);
82 if (!cin)
83 return bb_cat(argv);
84
85 if (ENABLE_FEATURE_USE_TERMIOS) {
86 cin_fileno = fileno(cin);
87 getTermSettings(cin_fileno, &initial_settings);
88 new_settings = initial_settings;
89 new_settings.c_lflag &= ~(ICANON | ECHO);
90 new_settings.c_cc[VMIN] = 1;
91 new_settings.c_cc[VTIME] = 0;
92 setTermSettings(cin_fileno, &new_settings);
93 bb_signals(0
94 + (1 << SIGINT)
95 + (1 << SIGQUIT)
96 + (1 << SIGTERM)
97 , gotsig);
98 }
99
100 do {
101 file = stdin;
102 if (*argv) {
103 file = fopen_or_warn(*argv, "r");
104 if (!file)
105 continue;
106 }
107 st.st_size = 0;
108 fstat(fileno(file), &st);
109
110 please_display_more_prompt = 0;
111 /* never returns w, h <= 1 */
112 get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
113 terminal_height -= 1;
114
115 len = 0;
116 lines = 0;
117 while (spaces || (c = getc(file)) != EOF) {
118 int wrap;
119 if (spaces)
120 spaces--;
121 loop_top:
122 if (input != 'r' && please_display_more_prompt) {
123 len = printf("--More-- ");
124 if (st.st_size != 0) {
125 uoff_t d = (uoff_t)st.st_size / 100;
126 if (d == 0)
127 d = 1;
128 len += printf("(%u%% of %"OFF_FMT"u bytes)",
129 (int) ((uoff_t)ftello(file) / d),
130 st.st_size);
131 }
132 fflush_all();
133
134 /*
135 * We've just displayed the "--More--" prompt, so now we need
136 * to get input from the user.
137 */
138 for (;;) {
139 input = getc(cin);
140 input = tolower(input);
141 if (!ENABLE_FEATURE_USE_TERMIOS)
142 printf("\033[A"); /* cursor up */
143 /* Erase the last message */
144 printf("\r%*s\r", len, "");
145
146 /* Due to various multibyte escape
147 * sequences, it's not ok to accept
148 * any input as a command to scroll
149 * the screen. We only allow known
150 * commands, else we show help msg. */
151 if (input == ' ' || input == '\n' || input == 'q' || input == 'r')
152 break;
153 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
154 }
155 len = 0;
156 lines = 0;
157 please_display_more_prompt = 0;
158
159 if (input == 'q')
160 goto end;
161
162 /* The user may have resized the terminal.
163 * Re-read the dimensions. */
164 if (ENABLE_FEATURE_USE_TERMIOS) {
165 get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height);
166 terminal_height -= 1;
167 }
168 }
169
170 /* Crudely convert tabs into spaces, which are
171 * a bajillion times easier to deal with. */
172 if (c == '\t') {
173 spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE;
174 c = ' ';
175 }
176
177 /*
178 * There are two input streams to worry about here:
179 *
180 * c : the character we are reading from the file being "mored"
181 * input: a character received from the keyboard
182 *
183 * If we hit a newline in the _file_ stream, we want to test and
184 * see if any characters have been hit in the _input_ stream. This
185 * allows the user to quit while in the middle of a file.
186 */
187 wrap = (++len > terminal_width);
188 if (c == '\n' || wrap) {
189 /* Then outputting this character
190 * will move us to a new line. */
191 if (++lines >= terminal_height || input == '\n')
192 please_display_more_prompt = 1;
193 len = 0;
194 }
195 if (c != '\n' && wrap) {
196 /* Then outputting this will also put a character on
197 * the beginning of that new line. Thus we first want to
198 * display the prompt (if any), so we skip the putchar()
199 * and go back to the top of the loop, without reading
200 * a new character. */
201 goto loop_top;
202 }
203 /* My small mind cannot fathom backspaces and UTF-8 */
204 putchar(c);
205 die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */
206 }
207 fclose(file);
208 fflush_all();
209 } while (*argv && *++argv);
210 end:
211 setTermSettings(cin_fileno, &initial_settings);
212 return 0;
213}
Note: See TracBrowser for help on using the repository browser.