Annotation of /trunk/mkinitrd-magellan/busybox/util-linux/more.c
Parent Directory | Revision Log
Revision 984 -
(hide annotations)
(download)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5328 byte(s)
Sun May 30 11:32:42 2010 UTC (13 years, 11 months ago) by niro
File MIME type: text/plain
File size: 5328 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | niro | 532 | /* 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 | niro | 816 | #include "libbb.h" |
18 | niro | 532 | |
19 | niro | 984 | /* Support for FEATURE_USE_TERMIOS */ |
20 | niro | 532 | |
21 | niro | 816 | struct globals { |
22 | int cin_fileno; | ||
23 | struct termios initial_settings; | ||
24 | struct termios new_settings; | ||
25 | }; | ||
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 | niro | 984 | #define setTermSettings(fd, argp) do { \ |
33 | if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ | ||
34 | } while(0) | ||
35 | niro | 816 | #define getTermSettings(fd, argp) tcgetattr(fd, argp) |
36 | niro | 532 | |
37 | niro | 816 | static void gotsig(int sig UNUSED_PARAM) |
38 | niro | 532 | { |
39 | niro | 816 | bb_putchar('\n'); |
40 | niro | 532 | setTermSettings(cin_fileno, &initial_settings); |
41 | niro | 816 | exit(EXIT_FAILURE); |
42 | niro | 532 | } |
43 | |||
44 | niro | 816 | #define CONVERTED_TAB_SIZE 8 |
45 | niro | 532 | |
46 | niro | 816 | int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
47 | int more_main(int argc UNUSED_PARAM, char **argv) | ||
48 | niro | 532 | { |
49 | niro | 816 | int c = c; /* for gcc */ |
50 | int lines; | ||
51 | int input = 0; | ||
52 | int spaces = 0; | ||
53 | int please_display_more_prompt; | ||
54 | niro | 532 | struct stat st; |
55 | FILE *file; | ||
56 | FILE *cin; | ||
57 | niro | 816 | int len; |
58 | unsigned terminal_width; | ||
59 | unsigned terminal_height; | ||
60 | niro | 532 | |
61 | niro | 816 | INIT_G(); |
62 | |||
63 | niro | 532 | argv++; |
64 | niro | 816 | /* 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 | niro | 532 | |
72 | niro | 984 | 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 | niro | 532 | |
88 | do { | ||
89 | file = stdin; | ||
90 | niro | 816 | if (*argv) { |
91 | niro | 532 | file = fopen_or_warn(*argv, "r"); |
92 | if (!file) | ||
93 | niro | 816 | continue; |
94 | niro | 532 | } |
95 | st.st_size = 0; | ||
96 | fstat(fileno(file), &st); | ||
97 | |||
98 | niro | 816 | please_display_more_prompt = 0; |
99 | /* never returns w, h <= 1 */ | ||
100 | niro | 532 | get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); |
101 | niro | 816 | terminal_height -= 1; |
102 | niro | 532 | |
103 | len = 0; | ||
104 | lines = 0; | ||
105 | niro | 816 | 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 | niro | 532 | len = printf("--More-- "); |
112 | niro | 816 | if (st.st_size > 0) { |
113 | niro | 984 | len += printf("(%u%% of %"OFF_FMT"u bytes)", |
114 | niro | 532 | (int) (ftello(file)*100 / st.st_size), |
115 | st.st_size); | ||
116 | } | ||
117 | niro | 984 | fflush_all(); |
118 | niro | 532 | |
119 | /* | ||
120 | * We've just displayed the "--More--" prompt, so now we need | ||
121 | * to get input from the user. | ||
122 | */ | ||
123 | niro | 816 | for (;;) { |
124 | input = getc(cin); | ||
125 | input = tolower(input); | ||
126 | niro | 984 | if (!ENABLE_FEATURE_USE_TERMIOS) |
127 | printf("\033[A"); /* cursor up */ | ||
128 | niro | 816 | /* 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 | niro | 532 | len = 0; |
141 | lines = 0; | ||
142 | niro | 816 | please_display_more_prompt = 0; |
143 | niro | 532 | |
144 | if (input == 'q') | ||
145 | goto end; | ||
146 | niro | 816 | |
147 | /* The user may have resized the terminal. | ||
148 | * Re-read the dimensions. */ | ||
149 | niro | 984 | if (ENABLE_FEATURE_USE_TERMIOS) { |
150 | get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height); | ||
151 | terminal_height -= 1; | ||
152 | } | ||
153 | niro | 532 | } |
154 | |||
155 | niro | 816 | /* 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 | niro | 532 | /* |
163 | * There are two input streams to worry about here: | ||
164 | * | ||
165 | niro | 816 | * c : the character we are reading from the file being "mored" |
166 | * input: a character received from the keyboard | ||
167 | niro | 532 | * |
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 | niro | 816 | 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 | niro | 532 | len = 0; |
179 | } | ||
180 | niro | 816 | 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 | niro | 532 | } |
191 | fclose(file); | ||
192 | niro | 984 | fflush_all(); |
193 | niro | 816 | } while (*argv && *++argv); |
194 | niro | 532 | end: |
195 | niro | 816 | setTermSettings(cin_fileno, &initial_settings); |
196 | niro | 532 | return 0; |
197 | } |