diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-15 20:42:52 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-08-15 20:42:52 +0000 |
commit | 033e592cbc96c150c67ac9be7df65e314be5c8f8 (patch) | |
tree | 0ec512a6215295775b28eb49a4150fadf101465e | |
parent | ab9c44b1a41c9a17cd0f8a8f1e5517756ccb8bf0 (diff) | |
download | busybox-w32-033e592cbc96c150c67ac9be7df65e314be5c8f8.tar.gz busybox-w32-033e592cbc96c150c67ac9be7df65e314be5c8f8.tar.bz2 busybox-w32-033e592cbc96c150c67ac9be7df65e314be5c8f8.zip |
more: by Tristan Schmelcher <tpkschme@engmail.uwaterloo.ca>:
- Fixed a number of deficiencies in the line wrapping.
- Fixed a bug where the page could scroll multiple times per keypress.
- Re-read terminal dimensions after user input, in case they
resized the terminal while we were waiting.
- Added an 'R' key to print the rest of the file without prompting.
- Crudely support tabs in the line-wrapping code by converting
them to 8 spaces.
-rw-r--r-- | util-linux/more.c | 108 |
1 files changed, 62 insertions, 46 deletions
diff --git a/util-linux/more.c b/util-linux/more.c index 4083d8eea..92ebdfea9 100644 --- a/util-linux/more.c +++ b/util-linux/more.c | |||
@@ -29,11 +29,11 @@ struct globals { | |||
29 | }; | 29 | }; |
30 | #define G (*(struct globals*)bb_common_bufsiz1) | 30 | #define G (*(struct globals*)bb_common_bufsiz1) |
31 | //#define G (*ptr_to_globals) | 31 | //#define G (*ptr_to_globals) |
32 | #define INIT_G() ((void)0) | ||
33 | //#define INIT_G() PTR_TO_GLOBALS = xzalloc(sizeof(G)) | ||
32 | #define initial_settings (G.initial_settings) | 34 | #define initial_settings (G.initial_settings) |
33 | #define new_settings (G.new_settings ) | 35 | #define new_settings (G.new_settings ) |
34 | #define cin_fileno (G.cin_fileno ) | 36 | #define cin_fileno (G.cin_fileno ) |
35 | #define INIT_G() ((void)0) | ||
36 | //#define INIT_G() PTR_TO_GLOBALS = xzalloc(sizeof(G)) | ||
37 | 37 | ||
38 | #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp) | 38 | #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp) |
39 | #define getTermSettings(fd, argp) tcgetattr(fd, argp) | 39 | #define getTermSettings(fd, argp) tcgetattr(fd, argp) |
@@ -50,16 +50,20 @@ static void gotsig(int sig) | |||
50 | #define setTermSettings(fd, argp) ((void)0) | 50 | #define setTermSettings(fd, argp) ((void)0) |
51 | #endif /* FEATURE_USE_TERMIOS */ | 51 | #endif /* FEATURE_USE_TERMIOS */ |
52 | 52 | ||
53 | #define CONVERTED_TAB_SIZE 8 | ||
53 | 54 | ||
54 | int more_main(int argc, char **argv); | 55 | int more_main(int argc, char **argv); |
55 | int more_main(int argc, char **argv) | 56 | int more_main(int argc, char **argv) |
56 | { | 57 | { |
57 | int c, lines, input = 0; | 58 | int c = c; /* for gcc */ |
58 | int please_display_more_prompt = 0; | 59 | int lines; |
60 | int input = 0; | ||
61 | int spaces = 0; | ||
62 | int please_display_more_prompt; | ||
59 | struct stat st; | 63 | struct stat st; |
60 | FILE *file; | 64 | FILE *file; |
61 | FILE *cin; | 65 | FILE *cin; |
62 | int len, page_height; | 66 | int len; |
63 | int terminal_width; | 67 | int terminal_width; |
64 | int terminal_height; | 68 | int terminal_height; |
65 | 69 | ||
@@ -87,7 +91,6 @@ int more_main(int argc, char **argv) | |||
87 | signal(SIGQUIT, gotsig); | 91 | signal(SIGQUIT, gotsig); |
88 | signal(SIGTERM, gotsig); | 92 | signal(SIGTERM, gotsig); |
89 | #endif | 93 | #endif |
90 | please_display_more_prompt = 2; | ||
91 | 94 | ||
92 | do { | 95 | do { |
93 | file = stdin; | 96 | file = stdin; |
@@ -99,19 +102,21 @@ int more_main(int argc, char **argv) | |||
99 | st.st_size = 0; | 102 | st.st_size = 0; |
100 | fstat(fileno(file), &st); | 103 | fstat(fileno(file), &st); |
101 | 104 | ||
102 | please_display_more_prompt &= ~1; | 105 | please_display_more_prompt = 0; |
103 | /* never returns w, h <= 1 */ | 106 | /* never returns w, h <= 1 */ |
104 | get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); | 107 | get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); |
105 | terminal_width -= 1; | ||
106 | terminal_height -= 1; | 108 | terminal_height -= 1; |
107 | 109 | ||
108 | len = 0; | 110 | len = 0; |
109 | lines = 0; | 111 | lines = 0; |
110 | page_height = terminal_height; | 112 | while (spaces || (c = getc(file)) != EOF) { |
111 | while ((c = getc(file)) != EOF) { | 113 | int wrap; |
112 | if ((please_display_more_prompt & 3) == 3) { | 114 | if (spaces) |
115 | spaces--; | ||
116 | loop_top: | ||
117 | if (input != 'r' && please_display_more_prompt) { | ||
113 | len = printf("--More-- "); | 118 | len = printf("--More-- "); |
114 | if (/*file != stdin &&*/ st.st_size > 0) { | 119 | if (st.st_size > 0) { |
115 | len += printf("(%d%% of %"OFF_FMT"d bytes)", | 120 | len += printf("(%d%% of %"OFF_FMT"d bytes)", |
116 | (int) (ftello(file)*100 / st.st_size), | 121 | (int) (ftello(file)*100 / st.st_size), |
117 | st.st_size); | 122 | st.st_size); |
@@ -122,23 +127,44 @@ int more_main(int argc, char **argv) | |||
122 | * We've just displayed the "--More--" prompt, so now we need | 127 | * We've just displayed the "--More--" prompt, so now we need |
123 | * to get input from the user. | 128 | * to get input from the user. |
124 | */ | 129 | */ |
125 | input = getc(cin); | 130 | for (;;) { |
131 | input = getc(cin); | ||
132 | input = tolower(input); | ||
126 | #if !ENABLE_FEATURE_USE_TERMIOS | 133 | #if !ENABLE_FEATURE_USE_TERMIOS |
127 | printf("\033[A"); /* up cursor */ | 134 | printf("\033[A"); /* up cursor */ |
128 | #endif | 135 | #endif |
129 | /* Erase the "More" message */ | 136 | /* Erase the last message */ |
130 | printf("\r%*s\r", len, ""); | 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 | } | ||
131 | len = 0; | 148 | len = 0; |
132 | lines = 0; | 149 | lines = 0; |
133 | /* Bottom line on page will become top line | 150 | please_display_more_prompt = 0; |
134 | * after one page forward. Thus -1: */ | ||
135 | page_height = terminal_height - 1; | ||
136 | please_display_more_prompt &= ~1; | ||
137 | 151 | ||
138 | if (input == 'q') | 152 | if (input == 'q') |
139 | goto end; | 153 | goto end; |
154 | |||
155 | /* The user may have resized the terminal. | ||
156 | * Re-read the dimensions. */ | ||
157 | get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height); | ||
158 | terminal_height -= 1; | ||
140 | } | 159 | } |
141 | 160 | ||
161 | /* Crudely convert tabs into spaces, which are | ||
162 | * a bajillion times easier to deal with. */ | ||
163 | if (c == '\t') { | ||
164 | spaces = CONVERTED_TAB_SIZE - 1; | ||
165 | c = ' '; | ||
166 | } | ||
167 | |||
142 | /* | 168 | /* |
143 | * There are two input streams to worry about here: | 169 | * There are two input streams to worry about here: |
144 | * | 170 | * |
@@ -149,34 +175,24 @@ int more_main(int argc, char **argv) | |||
149 | * see if any characters have been hit in the _input_ stream. This | 175 | * see if any characters have been hit in the _input_ stream. This |
150 | * allows the user to quit while in the middle of a file. | 176 | * allows the user to quit while in the middle of a file. |
151 | */ | 177 | */ |
152 | if (c == '\n') { | 178 | wrap = (++len > terminal_width); |
153 | /* increment by just one line if we are at | 179 | if (c == '\n' || wrap) { |
154 | * the end of this line */ | 180 | /* Then outputting this character |
155 | if (input == '\n') | 181 | * will move us to a new line. */ |
156 | please_display_more_prompt |= 1; | 182 | if (++lines >= terminal_height || input == '\n') |
157 | /* Adjust the terminal height for any overlap, so that | 183 | please_display_more_prompt = 1; |
158 | * no lines get lost off the top. */ | ||
159 | if (len >= terminal_width) { | ||
160 | int quot, rem; | ||
161 | quot = len / terminal_width; | ||
162 | rem = len - (quot * terminal_width); | ||
163 | page_height -= (quot - 1); | ||
164 | if (rem) | ||
165 | page_height--; | ||
166 | } | ||
167 | if (++lines >= page_height) { | ||
168 | please_display_more_prompt |= 1; | ||
169 | } | ||
170 | len = 0; | 184 | len = 0; |
171 | } | 185 | } |
172 | /* | 186 | if (c != '\n' && wrap) { |
173 | * If we just read a newline from the file being 'mored' and any | 187 | /* Then outputting this will also put a character on |
174 | * key other than a return is hit, scroll by one page | 188 | * the beginning of that new line. Thus we first want to |
175 | */ | 189 | * display the prompt (if any), so we skip the putchar() |
176 | putc(c, stdout); | 190 | * and go back to the top of the loop, without reading |
177 | /* My small mind cannot fathom tabs, backspaces, | 191 | * a new character. */ |
178 | * and UTF-8 */ | 192 | goto loop_top; |
179 | len++; | 193 | } |
194 | /* My small mind cannot fathom backspaces and UTF-8 */ | ||
195 | putchar(c); | ||
180 | } | 196 | } |
181 | fclose(file); | 197 | fclose(file); |
182 | fflush(stdout); | 198 | fflush(stdout); |