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