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