aboutsummaryrefslogtreecommitdiff
path: root/miscutils/less.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-24 07:14:17 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-24 07:14:17 +0000
commitf4dff773553da8b4a5a66205e920a82732156851 (patch)
treec9889bd051ff152f51a1e0056e1243063116e7c9 /miscutils/less.c
parent9ac9e55e3c1dd11bf007623ea672f7569366c186 (diff)
downloadbusybox-w32-f4dff773553da8b4a5a66205e920a82732156851.tar.gz
busybox-w32-f4dff773553da8b4a5a66205e920a82732156851.tar.bz2
busybox-w32-f4dff773553da8b4a5a66205e920a82732156851.zip
less: implement waiting for input using select(). Rather tricky business.
But we do not read entire input anymore up-front.
Diffstat (limited to 'miscutils/less.c')
-rw-r--r--miscutils/less.c970
1 files changed, 516 insertions, 454 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index 03b93973f..66158899d 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -26,26 +26,9 @@
26#include "xregex.h" 26#include "xregex.h"
27#endif 27#endif
28 28
29 29/* FIXME: currently doesn't work right */
30/* These are the escape sequences corresponding to special keys */ 30#undef ENABLE_FEATURE_LESS_FLAGCS
31#define REAL_KEY_UP 'A' 31#define ENABLE_FEATURE_LESS_FLAGCS 0
32#define REAL_KEY_DOWN 'B'
33#define REAL_KEY_RIGHT 'C'
34#define REAL_KEY_LEFT 'D'
35#define REAL_PAGE_UP '5'
36#define REAL_PAGE_DOWN '6'
37#define REAL_KEY_HOME '7'
38#define REAL_KEY_END '8'
39
40/* These are the special codes assigned by this program to the special keys */
41#define KEY_UP 20
42#define KEY_DOWN 21
43#define KEY_RIGHT 22
44#define KEY_LEFT 23
45#define PAGE_UP 24
46#define PAGE_DOWN 25
47#define KEY_HOME 26
48#define KEY_END 27
49 32
50/* The escape codes for highlighted and normal text */ 33/* The escape codes for highlighted and normal text */
51#define HIGHLIGHT "\033[7m" 34#define HIGHLIGHT "\033[7m"
@@ -55,124 +38,103 @@
55/* The escape code to clear to end of line */ 38/* The escape code to clear to end of line */
56#define CLEAR_2_EOL "\033[K" 39#define CLEAR_2_EOL "\033[K"
57 40
58#define MAXLINES CONFIG_FEATURE_LESS_MAXLINES 41/* These are the escape sequences corresponding to special keys */
42enum {
43 REAL_KEY_UP = 'A',
44 REAL_KEY_DOWN = 'B',
45 REAL_KEY_RIGHT = 'C',
46 REAL_KEY_LEFT = 'D',
47 REAL_PAGE_UP = '5',
48 REAL_PAGE_DOWN = '6',
49 REAL_KEY_HOME = '7',
50 REAL_KEY_END = '8',
51
52/* These are the special codes assigned by this program to the special keys */
53 KEY_UP = 20,
54 KEY_DOWN = 21,
55 KEY_RIGHT = 22,
56 KEY_LEFT = 23,
57 PAGE_UP = 24,
58 PAGE_DOWN = 25,
59 KEY_HOME = 26,
60 KEY_END = 27,
61
62/* Absolute max of lines eaten */
63 MAXLINES = CONFIG_FEATURE_LESS_MAXLINES,
64
65/* This many "after the end" lines we will show (at max) */
66 TILDES = 1,
67};
68
69static unsigned max_displayed_line;
70static unsigned width;
71static const char *empty_line_marker = "~";
59 72
60static int height;
61static int width;
62static char **files;
63static char *filename; 73static char *filename;
74static char **files;
75static unsigned num_files = 1;
76static unsigned current_file = 1;
64static const char **buffer; 77static const char **buffer;
65static char **flines; 78static const char **flines;
66static int current_file = 1; 79static int cur_fline; /* signed */
67static int line_pos; 80static unsigned max_fline;
68static int num_flines; 81static unsigned max_lineno; /* this one tracks linewrap */
69static int num_files = 1; 82
70static const char *empty_line_marker = "~"; 83static ssize_t eof_error = 1; /* eof if 0, error if < 0 */
84static char terminated = 1;
85static size_t readpos;
86static size_t readeof;
87/* last position in last line, taking into account tabs */
88static size_t linepos;
71 89
72/* Command line options */ 90/* Command line options */
73#define FLAG_E 1 91enum {
74#define FLAG_M (1<<1) 92 FLAG_E = 1,
75#define FLAG_m (1<<2) 93 FLAG_M = 1 << 1,
76#define FLAG_N (1<<3) 94 FLAG_m = 1 << 2,
77#define FLAG_TILDE (1<<4) 95 FLAG_N = 1 << 3,
96 FLAG_TILDE = 1 << 4,
78/* hijack command line options variable for internal state vars */ 97/* hijack command line options variable for internal state vars */
79#define LESS_STATE_MATCH_BACKWARDS (1<<6) 98 LESS_STATE_MATCH_BACKWARDS = 1 << 15,
99};
80 100
81#if ENABLE_FEATURE_LESS_MARKS 101#if ENABLE_FEATURE_LESS_MARKS
82static int mark_lines[15][2]; 102static unsigned mark_lines[15][2];
83static int num_marks; 103static unsigned num_marks;
84#endif 104#endif
85 105
86#if ENABLE_FEATURE_LESS_REGEXP 106#if ENABLE_FEATURE_LESS_REGEXP
87static int *match_lines; 107static unsigned *match_lines;
88static int match_pos; 108static int match_pos; /* signed! */
89static int num_matches; 109static unsigned num_matches;
90static regex_t pattern; 110static regex_t pattern;
91static int pattern_valid; 111static unsigned pattern_valid;
92#endif 112#endif
93 113
94/* Needed termios structures */
95static struct termios term_orig, term_vi; 114static struct termios term_orig, term_vi;
96 115
97/* File pointer to get input from */ 116/* File pointer to get input from */
98static FILE *inp; 117static int kbd_fd;
99 118
100/* Reset terminal input to normal */ 119/* Reset terminal input to normal */
101static void set_tty_cooked(void) 120static void set_tty_cooked(void)
102{ 121{
103 fflush(stdout); 122 fflush(stdout);
104 tcsetattr(fileno(inp), TCSANOW, &term_orig); 123 tcsetattr(kbd_fd, TCSANOW, &term_orig);
105} 124}
106 125
107/* Exit the program gracefully */ 126/* Exit the program gracefully */
108static void tless_exit(int code) 127static void less_exit(int code)
109{ 128{
110 /* TODO: We really should save the terminal state when we start, 129 /* TODO: We really should save the terminal state when we start,
111 and restore it when we exit. Less does this with the 130 * and restore it when we exit. Less does this with the
112 "ti" and "te" termcap commands; can this be done with 131 * "ti" and "te" termcap commands; can this be done with
113 only termios.h? */ 132 * only termios.h? */
114 133
115 putchar('\n'); 134 putchar('\n');
116 fflush_stdout_and_exit(code); 135 fflush_stdout_and_exit(code);
117} 136}
118 137
119/* Grab a character from input without requiring the return key. If the
120 character is ASCII \033, get more characters and assign certain sequences
121 special return codes. Note that this function works best with raw input. */
122static int tless_getch(void)
123{
124 int input;
125 /* Set terminal input to raw mode (taken from vi.c) */
126 tcsetattr(fileno(inp), TCSANOW, &term_vi);
127 again:
128 input = getc(inp);
129 /* Detect escape sequences (i.e. arrow keys) and handle
130 them accordingly */
131
132 if (input == '\033' && getc(inp) == '[') {
133 unsigned i;
134 input = getc(inp);
135 set_tty_cooked();
136
137 i = input - REAL_KEY_UP;
138 if (i < 4)
139 return 20 + i;
140 i = input - REAL_PAGE_UP;
141 if (i < 4)
142 return 24 + i;
143 return 0; /* ?? */
144 }
145 /* Reject almost all control chars */
146 if (input < ' ' && input != 0x0d && input != 8) goto again;
147 set_tty_cooked();
148 return input;
149}
150
151static char* tless_gets(int sz)
152{
153 int c;
154 int i = 0;
155 char *result = xzalloc(1);
156 while (1) {
157 c = tless_getch();
158 if (c == 0x0d)
159 return result;
160 if (c == 0x7f) c = 8;
161 if (c == 8 && i) {
162 printf("\x8 \x8");
163 i--;
164 }
165 if (c < ' ')
166 continue;
167 if (i >= width - sz - 1)
168 continue; /* len limit */
169 putchar(c);
170 result[i++] = c;
171 result = xrealloc(result, i+1);
172 result[i] = '\0';
173 }
174}
175
176/* Move the cursor to a position (x,y), where (0,0) is the 138/* Move the cursor to a position (x,y), where (0,0) is the
177 top-left corner of the console */ 139 top-left corner of the console */
178static void move_cursor(int line, int row) 140static void move_cursor(int line, int row)
@@ -182,7 +144,7 @@ static void move_cursor(int line, int row)
182 144
183static void clear_line(void) 145static void clear_line(void)
184{ 146{
185 printf("\033[%u;0H" CLEAR_2_EOL, height); 147 printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2);
186} 148}
187 149
188static void print_hilite(const char *str) 150static void print_hilite(const char *str)
@@ -193,90 +155,116 @@ static void print_hilite(const char *str)
193static void print_statusline(const char *str) 155static void print_statusline(const char *str)
194{ 156{
195 clear_line(); 157 clear_line();
196 printf(HIGHLIGHT"%.*s"NORMAL, width-1, str); 158 printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
197} 159}
198 160
199static void data_readlines(void) 161static void read_lines(void)
200{ 162{
201 unsigned i, pos; 163 /* TODO: regexp match array should be updated too */
202 unsigned lineno = 1;
203 int w = width;
204 char terminated, last_terminated = 1;
205 char *current_line, *p;
206 FILE *fp;
207 164
208 if (filename) 165#define readbuf bb_common_bufsiz1
209 fp = xfopen(filename, "r"); 166 char *current_line, *p;
210 else { 167 int w = width;
211 /* "less" with no arguments in argv[] */ 168 char last_terminated = terminated;
212 fp = stdin;
213 /* For status line only */
214 filename = xstrdup(bb_msg_standard_input);
215 }
216 169
217 flines = NULL; 170 if (option_mask32 & FLAG_N)
218 if (option_mask32 & FLAG_N) {
219 w -= 8; 171 w -= 8;
172
173 current_line = xmalloc(w);
174 p = current_line;
175 max_fline += last_terminated;
176 if (!last_terminated) {
177 const char *cp = flines[max_fline];
178 if (option_mask32 & FLAG_N)
179 cp += 8;
180 strcpy(current_line, cp);
181 p += strlen(current_line);
220 } 182 }
221 for (i = 0; !feof(fp) && i <= MAXLINES; i++) { 183
222 flines = xrealloc(flines, (i+1) * sizeof(char *)); 184 while (1) {
223 current_line = xmalloc(w);
224 again: 185 again:
225 p = current_line; 186 *p = '\0';
226 pos = 0;
227 terminated = 0; 187 terminated = 0;
228 while (1) { 188 while (1) {
229 int c = getc(fp); 189 char c;
230 if (c == '\t') pos += (pos^7) & 7; 190 if (readpos >= readeof) {
231 pos++; 191ndelay_on(0);
232 if (pos >= w) { ungetc(c, fp); break; } 192 eof_error = safe_read(0, readbuf, sizeof(readbuf));
233 if (c == EOF) break; 193ndelay_off(0);
194 readpos = 0;
195 readeof = eof_error;
196 if (eof_error < 0) {
197 readeof = 0;
198 if (errno != EAGAIN)
199 print_statusline("read error");
200 }
201 if (eof_error <= 0) {
202 goto reached_eof;
203 }
204 }
205 c = readbuf[readpos];
206 if (c == '\t')
207 linepos += (linepos^7) & 7;
208 linepos++;
209 if (linepos >= w)
210 break;
211 readpos++;
234 if (c == '\n') { terminated = 1; break; } 212 if (c == '\n') { terminated = 1; break; }
235 /* NUL is substituted by '\n'! */ 213 /* NUL is substituted by '\n'! */
236 if (c == '\0') c = '\n'; 214 if (c == '\0') c = '\n';
237 *p++ = c; 215 *p++ = c;
216 *p = '\0';
238 } 217 }
239 *p = '\0';
240 if (fp != stdin)
241 die_if_ferror(fp, filename);
242
243 /* Corner case: linewrap with only "" wrapping to next line */ 218 /* Corner case: linewrap with only "" wrapping to next line */
244 /* Looks ugly on screen, so we do not store this empty line */ 219 /* Looks ugly on screen, so we do not store this empty line */
245 if (!last_terminated && !current_line[0]) { 220 if (!last_terminated && !current_line[0]) {
246 last_terminated = 1; 221 last_terminated = 1;
247 lineno++; 222 max_lineno++;
248 goto again; 223 goto again;
249 } 224 }
250 225 reached_eof:
251 last_terminated = terminated; 226 last_terminated = terminated;
227 flines = xrealloc(flines, (max_fline+1) * sizeof(char *));
252 if (option_mask32 & FLAG_N) { 228 if (option_mask32 & FLAG_N) {
253 /* Width of 7 preserves tab spacing in the text */ 229 /* Width of 7 preserves tab spacing in the text */
254 flines[i] = xasprintf( 230 flines[max_fline] = xasprintf(
255 (lineno <= 9999999) ? "%7u %s" : "%07u %s", 231 (max_lineno <= 9999999) ? "%7u %s" : "%07u %s",
256 lineno % 10000000, current_line); 232 max_lineno % 10000000, current_line);
257 free(current_line); 233 free(current_line);
258 if (terminated) 234 if (terminated)
259 lineno++; 235 max_lineno++;
260 } else { 236 } else {
261 flines[i] = xrealloc(current_line, strlen(current_line)+1); 237 flines[max_fline] = xrealloc(current_line, strlen(current_line)+1);
262 } 238 }
239 if (max_fline >= MAXLINES)
240 break;
241 if (max_fline > cur_fline + max_displayed_line)
242 break;
243 if (eof_error <= 0) {
244 if (eof_error < 0 && errno == EAGAIN) {
245 /* not yet eof or error, reset flag (or else
246 * we will hog CPU - select() will return
247 * immediately */
248 eof_error = 1;
249 }
250 break;
251 }
252 max_fline++;
253 current_line = xmalloc(w);
254 p = current_line;
255 linepos = 0;
263 } 256 }
264 num_flines = i - 1; /* buggie: 'num_flines' must be 'max_fline' */ 257#undef readbuf
265
266 /* Reset variables for a new file */
267
268 line_pos = 0;
269
270 fclose(fp);
271} 258}
272 259
273#if ENABLE_FEATURE_LESS_FLAGS 260#if ENABLE_FEATURE_LESS_FLAGS
274 261
275/* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes 262/* Interestingly, writing calc_percent as a function saves around 32 bytes
276 * on my build. */ 263 * on my build. */
277static int calc_percent(void) 264static int calc_percent(void)
278{ 265{
279 return ((100 * (line_pos + height - 2) / num_flines) + 1); 266 unsigned p = 100 * (cur_fline + max_displayed_line) / (max_fline + 1);
267 return p <= 100 ? p : 100;
280} 268}
281 269
282/* Print a status line if -M was specified */ 270/* Print a status line if -M was specified */
@@ -289,16 +277,16 @@ static void m_status_print(void)
289 if (num_files > 1) 277 if (num_files > 1)
290 printf(" (file %i of %i)", current_file, num_files); 278 printf(" (file %i of %i)", current_file, num_files);
291 printf(" lines %i-%i/%i ", 279 printf(" lines %i-%i/%i ",
292 line_pos + 1, line_pos + height - 1, 280 cur_fline + 1, cur_fline + max_displayed_line + 1,
293 num_flines + 1); 281 max_fline + 1);
294 if (line_pos >= num_flines - height + 2) { 282 if (cur_fline >= max_fline - max_displayed_line) {
295 printf("(END)"NORMAL); 283 printf("(END)"NORMAL);
296 if (num_files > 1 && current_file != num_files) 284 if (num_files > 1 && current_file != num_files)
297 printf(HIGHLIGHT" - next: %s "NORMAL, files[current_file]); 285 printf(HIGHLIGHT" - next: %s"NORMAL, files[current_file]);
298 return; 286 return;
299 } 287 }
300 percentage = calc_percent(); 288 percentage = calc_percent();
301 printf("%i%% "NORMAL, percentage); 289 printf("%i%%"NORMAL, percentage);
302} 290}
303 291
304#endif 292#endif
@@ -318,15 +306,15 @@ static void status_print(void)
318#endif 306#endif
319 307
320 clear_line(); 308 clear_line();
321 if (line_pos && line_pos < num_flines - height + 2) { 309 if (cur_fline && cur_fline < max_fline - max_displayed_line) {
322 putchar(':'); 310 putchar(':');
323 return; 311 return;
324 } 312 }
325 p = "(END)"; 313 p = "(END)";
326 if (!line_pos) 314 if (!cur_fline)
327 p = filename; 315 p = filename;
328 if (num_files > 1) { 316 if (num_files > 1) {
329 printf(HIGHLIGHT"%s (file %i of %i) "NORMAL, 317 printf(HIGHLIGHT"%s (file %i of %i)"NORMAL,
330 p, current_file, num_files); 318 p, current_file, num_files);
331 return; 319 return;
332 } 320 }
@@ -423,7 +411,7 @@ static void print_ascii(const char *str)
423 do { 411 do {
424 if (*str == 0x7f) 412 if (*str == 0x7f)
425 *p++ = '?'; 413 *p++ = '?';
426 else if (*str == 0x9b) 414 else if (*str == (char)0x9b)
427 /* VT100's CSI, aka Meta-ESC. Who's inventor? */ 415 /* VT100's CSI, aka Meta-ESC. Who's inventor? */
428 /* I want to know who committed this sin */ 416 /* I want to know who committed this sin */
429 *p++ = '{'; 417 *p++ = '{';
@@ -443,7 +431,7 @@ static void buffer_print(void)
443 int i; 431 int i;
444 432
445 move_cursor(0, 0); 433 move_cursor(0, 0);
446 for (i = 0; i < height - 1; i++) 434 for (i = 0; i <= max_displayed_line; i++)
447 if (pattern_valid) 435 if (pattern_valid)
448 print_found(buffer[i]); 436 print_found(buffer[i]);
449 else 437 else
@@ -451,111 +439,194 @@ static void buffer_print(void)
451 status_print(); 439 status_print();
452} 440}
453 441
454/* Initialise the buffer */ 442static void buffer_fill_and_print(void)
455static void buffer_init(void)
456{ 443{
457 int i; 444 int i;
458 445 for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) {
459 /* Fill the buffer until the end of the file or the 446 buffer[i] = flines[cur_fline + i];
460 end of the buffer is reached */
461 for (i = 0; i < height - 1 && i <= num_flines; i++) {
462 buffer[i] = flines[i];
463 } 447 }
464 448 for (; i <= max_displayed_line; i++) {
465 /* If the buffer still isn't full, fill it with blank lines */
466 for (; i < height - 1; i++) {
467 buffer[i] = empty_line_marker; 449 buffer[i] = empty_line_marker;
468 } 450 }
451 buffer_print();
469} 452}
470 453
471/* Move the buffer up and down in the file in order to scroll */ 454/* Move the buffer up and down in the file in order to scroll */
472static void buffer_down(int nlines) 455static void buffer_down(int nlines)
473{ 456{
474 int i; 457 int diff;
458 cur_fline += nlines;
459 read_lines();
475 460
476 if (line_pos + (height - 3) + nlines < num_flines) { 461 if (cur_fline + max_displayed_line > max_fline + TILDES) {
477 line_pos += nlines; 462 cur_fline -= nlines;
478 for (i = 0; i < (height - 1); i++) { 463 diff = max_fline - (cur_fline + max_displayed_line) + TILDES;
479 buffer[i] = flines[line_pos + i];
480 }
481 } else {
482 /* As the number of lines requested was too large, we just move 464 /* As the number of lines requested was too large, we just move
483 to the end of the file */ 465 to the end of the file */
484 while (line_pos + (height - 3) + 1 < num_flines) { 466 if (diff > 0)
485 line_pos += 1; 467 cur_fline += diff;
486 for (i = 0; i < (height - 1); i++) {
487 buffer[i] = flines[line_pos + i];
488 }
489 }
490 } 468 }
491 469 buffer_fill_and_print();
492 /* We exit if the -E flag has been set */
493 if ((option_mask32 & FLAG_E) && (line_pos + (height - 2) == num_flines))
494 tless_exit(0);
495} 470}
496 471
497static void buffer_up(int nlines) 472static void buffer_up(int nlines)
498{ 473{
499 int i; 474 cur_fline -= nlines;
475 if (cur_fline < 0) cur_fline = 0;
476 read_lines();
477 buffer_fill_and_print();
478}
500 479
501 line_pos -= nlines; 480static void buffer_line(int linenum)
502 if (line_pos < 0) line_pos = 0; 481{
503 for (i = 0; i < height - 1; i++) { 482 if (linenum + max_displayed_line > max_fline)
504 if (line_pos + i <= num_flines) { 483 linenum = max_fline - max_displayed_line + TILDES;
505 buffer[i] = flines[line_pos + i]; 484 if (linenum < 0) linenum = 0;
506 } else { 485 cur_fline = linenum;
507 buffer[i] = empty_line_marker; 486 buffer_fill_and_print();
508 } 487}
488
489static void open_file_and_read_lines(void)
490{
491 if (filename) {
492 int fd = xopen(filename, O_RDONLY);
493 dup2(fd, 0);
494 if (fd) close(fd);
495 } else {
496 /* "less" with no arguments in argv[] */
497 /* For status line only */
498 filename = xstrdup(bb_msg_standard_input);
509 } 499 }
500 readpos = 0;
501 readeof = 0;
502 linepos = 0;
503 terminated = 1;
504 read_lines();
510} 505}
511 506
512static void buffer_line(int linenum) 507/* Reinitialize everything for a new file - free the memory and start over */
508static void reinitialize(void)
513{ 509{
514 int i; 510 int i;
515 511
516 if (linenum < 0 || linenum > num_flines) { 512 if (flines) {
517 clear_line(); 513 for (i = 0; i <= max_fline; i++)
518 printf(HIGHLIGHT"%s%u"NORMAL, "Cannot seek to line ", linenum + 1); 514 free((void*)(flines[i]));
519 return; 515 free(flines);
516 flines = NULL;
520 } 517 }
521 518
522 for (i = 0; i < height - 1; i++) { 519 max_fline = -1;
523 if (linenum + i <= num_flines) 520 cur_fline = 0;
524 buffer[i] = flines[linenum + i]; 521 max_lineno = 0;
525 else { 522 open_file_and_read_lines();
526 buffer[i] = empty_line_marker; 523 buffer_fill_and_print();
527 } 524}
525
526static char* getch_nowait(void)
527{
528 static char input[16];
529 ssize_t sz;
530 fd_set readfds;
531 again:
532 fflush(stdout);
533 FD_ZERO(&readfds);
534 if (max_fline <= cur_fline + max_displayed_line && eof_error > 0) {
535 /* We are interested in stdin */
536 FD_SET(0, &readfds);
528 } 537 }
529 line_pos = linenum; 538 FD_SET(kbd_fd, &readfds);
530 buffer_print(); 539 tcsetattr(kbd_fd, TCSANOW, &term_vi);
540 select(kbd_fd + 1, &readfds, NULL, NULL, NULL);
541
542 input[0] = '\0';
543 ndelay_on(kbd_fd);
544 sz = read(kbd_fd, input, sizeof(input));
545 ndelay_off(kbd_fd);
546 if (sz < 0) {
547 /* No keyboard input, but we have input on stdin! */
548 if (errno != EAGAIN) /* Huh?? */
549 return input;
550 read_lines();
551 buffer_fill_and_print();
552 goto again;
553 }
554 return input;
531} 555}
532 556
533/* Reinitialise everything for a new file - free the memory and start over */ 557/* Grab a character from input without requiring the return key. If the
534static void reinitialise(void) 558 character is ASCII \033, get more characters and assign certain sequences
559 special return codes. Note that this function works best with raw input. */
560static int less_getch(void)
535{ 561{
536 int i; 562 char *input;
563 unsigned i;
564 again:
565 input = getch_nowait();
566 /* Detect escape sequences (i.e. arrow keys) and handle
567 * them accordingly */
537 568
538 for (i = 0; i <= num_flines; i++) 569 if (input[0] == '\033' && input[1] == '[') {
539 free(flines[i]); 570 set_tty_cooked();
540 free(flines); 571 i = input[2] - REAL_KEY_UP;
572 if (i < 4)
573 return 20 + i;
574 i = input[2] - REAL_PAGE_UP;
575 if (i < 4)
576 return 24 + i;
577 return 0;
578 }
579 /* Reject almost all control chars */
580 i = input[0];
581 if (i < ' ' && i != 0x0d && i != 8) goto again;
582 set_tty_cooked();
583 return i;
584}
541 585
542 data_readlines(); 586static char* less_gets(int sz)
543 buffer_init(); 587{
544 buffer_print(); 588 char c;
589 int i = 0;
590 char *result = xzalloc(1);
591 while (1) {
592 fflush(stdout);
593
594 /* I be damned if I know why is it needed *repeatedly*,
595 * but it is needed. Is it because of stdio? */
596 tcsetattr(kbd_fd, TCSANOW, &term_vi);
597
598 read(kbd_fd, &c, 1);
599 if (c == 0x0d)
600 return result;
601 if (c == 0x7f)
602 c = 8;
603 if (c == 8 && i) {
604 printf("\x8 \x8");
605 i--;
606 }
607 if (c < ' ')
608 continue;
609 if (i >= width - sz - 1)
610 continue; /* len limit */
611 putchar(c);
612 result[i++] = c;
613 result = xrealloc(result, i+1);
614 result[i] = '\0';
615 }
545} 616}
546 617
547static void examine_file(void) 618static void examine_file(void)
548{ 619{
549 print_statusline("Examine: "); 620 print_statusline("Examine: ");
550 free(filename); 621 free(filename);
551 filename = tless_gets(sizeof("Examine: ")-1); 622 filename = less_gets(sizeof("Examine: ")-1);
552 /* files start by = argv. why we assume that argv is infinitely long?? 623 /* files start by = argv. why we assume that argv is infinitely long??
553 files[num_files] = filename; 624 files[num_files] = filename;
554 current_file = num_files + 1; 625 current_file = num_files + 1;
555 num_files++; */ 626 num_files++; */
556 files[0] = filename; 627 files[0] = filename;
557 num_files = current_file = 1; 628 num_files = current_file = 1;
558 reinitialise(); 629 reinitialize();
559} 630}
560 631
561/* This function changes the file currently being paged. direction can be one of the following: 632/* This function changes the file currently being paged. direction can be one of the following:
@@ -569,7 +640,7 @@ static void change_file(int direction)
569 current_file = direction ? current_file + direction : 1; 640 current_file = direction ? current_file + direction : 1;
570 free(filename); 641 free(filename);
571 filename = xstrdup(files[current_file - 1]); 642 filename = xstrdup(files[current_file - 1]);
572 reinitialise(); 643 reinitialize();
573 } else { 644 } else {
574 print_statusline(direction > 0 ? "No next file" : "No previous file"); 645 print_statusline(direction > 0 ? "No next file" : "No previous file");
575 } 646 }
@@ -579,19 +650,20 @@ static void remove_current_file(void)
579{ 650{
580 int i; 651 int i;
581 652
653 if (num_files < 2)
654 return;
655
582 if (current_file != 1) { 656 if (current_file != 1) {
583 change_file(-1); 657 change_file(-1);
584 for (i = 3; i <= num_files; i++) 658 for (i = 3; i <= num_files; i++)
585 files[i - 2] = files[i - 1]; 659 files[i - 2] = files[i - 1];
586 num_files--; 660 num_files--;
587 buffer_print();
588 } else { 661 } else {
589 change_file(1); 662 change_file(1);
590 for (i = 2; i <= num_files; i++) 663 for (i = 2; i <= num_files; i++)
591 files[i - 2] = files[i - 1]; 664 files[i - 2] = files[i - 1];
592 num_files--; 665 num_files--;
593 current_file--; 666 current_file--;
594 buffer_print();
595 } 667 }
596} 668}
597 669
@@ -602,33 +674,31 @@ static void colon_process(void)
602 /* Clear the current line and print a prompt */ 674 /* Clear the current line and print a prompt */
603 print_statusline(" :"); 675 print_statusline(" :");
604 676
605 keypress = tless_getch(); 677 keypress = less_getch();
606 switch (keypress) { 678 switch (keypress) {
607 case 'd': 679 case 'd':
608 remove_current_file(); 680 remove_current_file();
609 break; 681 break;
610 case 'e': 682 case 'e':
611 examine_file(); 683 examine_file();
612 break; 684 break;
613#if ENABLE_FEATURE_LESS_FLAGS 685#if ENABLE_FEATURE_LESS_FLAGS
614 case 'f': 686 case 'f':
615 m_status_print(); 687 m_status_print();
616 break; 688 break;
617#endif 689#endif
618 case 'n': 690 case 'n':
619 change_file(1); 691 change_file(1);
620 break; 692 break;
621 case 'p': 693 case 'p':
622 change_file(-1); 694 change_file(-1);
623 break; 695 break;
624 case 'q': 696 case 'q':
625 tless_exit(0); 697 less_exit(0);
626 break; 698 break;
627 case 'x': 699 case 'x':
628 change_file(0); 700 change_file(0);
629 break; 701 break;
630 default:
631 break;
632 } 702 }
633} 703}
634 704
@@ -638,7 +708,7 @@ static int normalize_match_pos(int match)
638 if (match >= num_matches) 708 if (match >= num_matches)
639 match_pos = num_matches - 1; 709 match_pos = num_matches - 1;
640 if (match < 0) 710 if (match < 0)
641 return (match_pos = 0); 711 match_pos = 0;
642 return match_pos; 712 return match_pos;
643} 713}
644 714
@@ -654,8 +724,8 @@ static void regex_process(void)
654 char *uncomp_regex, *err; 724 char *uncomp_regex, *err;
655 725
656 /* Reset variables */ 726 /* Reset variables */
657 match_lines = xrealloc(match_lines, sizeof(int)); 727 free(match_lines);
658 match_lines[0] = -1; 728 match_lines = NULL;
659 match_pos = 0; 729 match_pos = 0;
660 num_matches = 0; 730 num_matches = 0;
661 if (pattern_valid) { 731 if (pattern_valid) {
@@ -666,8 +736,8 @@ static void regex_process(void)
666 /* Get the uncompiled regular expression from the user */ 736 /* Get the uncompiled regular expression from the user */
667 clear_line(); 737 clear_line();
668 putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/'); 738 putchar((option_mask32 & LESS_STATE_MATCH_BACKWARDS) ? '?' : '/');
669 uncomp_regex = tless_gets(1); 739 uncomp_regex = less_gets(1);
670 if (/*!uncomp_regex ||*/ !uncomp_regex[0]) { 740 if (!uncomp_regex[0]) {
671 free(uncomp_regex); 741 free(uncomp_regex);
672 buffer_print(); 742 buffer_print();
673 return; 743 return;
@@ -684,19 +754,19 @@ static void regex_process(void)
684 pattern_valid = 1; 754 pattern_valid = 1;
685 755
686 /* Run the regex on each line of the current file */ 756 /* Run the regex on each line of the current file */
687 for (match_pos = 0; match_pos <= num_flines; match_pos++) { 757 for (match_pos = 0; match_pos <= max_fline; match_pos++) {
688 if (regexec(&pattern, flines[match_pos], 0, NULL, 0) == 0) { 758 if (regexec(&pattern, flines[match_pos], 0, NULL, 0) == 0) {
689 match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int)); 759 match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
690 match_lines[num_matches++] = match_pos; 760 match_lines[num_matches++] = match_pos;
691 } 761 }
692 } 762 }
693 763
694 if (num_matches == 0 || num_flines <= height - 2) { 764 if (num_matches == 0 || max_fline <= max_displayed_line) {
695 buffer_print(); 765 buffer_print();
696 return; 766 return;
697 } 767 }
698 for (match_pos = 0; match_pos < num_matches; match_pos++) { 768 for (match_pos = 0; match_pos < num_matches; match_pos++) {
699 if (match_lines[match_pos] > line_pos) 769 if (match_lines[match_pos] > cur_fline)
700 break; 770 break;
701 } 771 }
702 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) match_pos--; 772 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) match_pos--;
@@ -719,7 +789,7 @@ static void number_process(int first_digit)
719 789
720 /* Receive input until a letter is given */ 790 /* Receive input until a letter is given */
721 while (i < sizeof(num_input)-1) { 791 while (i < sizeof(num_input)-1) {
722 num_input[i] = tless_getch(); 792 num_input[i] = less_getch();
723 if (!num_input[i] || !isdigit(num_input[i])) 793 if (!num_input[i] || !isdigit(num_input[i]))
724 break; 794 break;
725 putchar(num_input[i]); 795 putchar(num_input[i]);
@@ -738,34 +808,38 @@ static void number_process(int first_digit)
738 808
739 /* We now know the number and the letter entered, so we process them */ 809 /* We now know the number and the letter entered, so we process them */
740 switch (keypress) { 810 switch (keypress) {
741 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015': 811 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
742 buffer_down(num); 812 buffer_down(num);
743 break; 813 buffer_print();
744 case KEY_UP: case 'b': case 'w': case 'y': case 'u': 814 break;
745 buffer_up(num); 815 case KEY_UP: case 'b': case 'w': case 'y': case 'u':
746 break; 816 buffer_up(num);
747 case 'g': case '<': case 'G': case '>': 817 buffer_print();
748 if (num_flines >= height - 2) 818 break;
749 buffer_line(num - 1); 819 case 'g': case '<': case 'G': case '>':
750 break; 820 cur_fline = num + max_displayed_line;
751 case 'p': case '%': 821 read_lines();
752 buffer_line(((num / 100) * num_flines) - 1); 822 buffer_line(num - 1);
753 break; 823 break;
824 case 'p': case '%':
825 num = num * (max_fline / 100); /* + max_fline / 2; */
826 cur_fline = num + max_displayed_line;
827 read_lines();
828 buffer_line(num);
829 break;
754#if ENABLE_FEATURE_LESS_REGEXP 830#if ENABLE_FEATURE_LESS_REGEXP
755 case 'n': 831 case 'n':
756 goto_match(match_pos + num); 832 goto_match(match_pos + num);
757 break; 833 break;
758 case '/': 834 case '/':
759 option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS; 835 option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS;
760 regex_process(); 836 regex_process();
761 break; 837 break;
762 case '?': 838 case '?':
763 option_mask32 |= LESS_STATE_MATCH_BACKWARDS; 839 option_mask32 |= LESS_STATE_MATCH_BACKWARDS;
764 regex_process(); 840 regex_process();
765 break; 841 break;
766#endif 842#endif
767 default:
768 break;
769 } 843 }
770} 844}
771 845
@@ -776,23 +850,21 @@ static void flag_change(void)
776 850
777 clear_line(); 851 clear_line();
778 putchar('-'); 852 putchar('-');
779 keypress = tless_getch(); 853 keypress = less_getch();
780 854
781 switch (keypress) { 855 switch (keypress) {
782 case 'M': 856 case 'M':
783 option_mask32 ^= FLAG_M; 857 option_mask32 ^= FLAG_M;
784 break; 858 break;
785 case 'm': 859 case 'm':
786 option_mask32 ^= FLAG_m; 860 option_mask32 ^= FLAG_m;
787 break; 861 break;
788 case 'E': 862 case 'E':
789 option_mask32 ^= FLAG_E; 863 option_mask32 ^= FLAG_E;
790 break; 864 break;
791 case '~': 865 case '~':
792 option_mask32 ^= FLAG_TILDE; 866 option_mask32 ^= FLAG_TILDE;
793 break; 867 break;
794 default:
795 break;
796 } 868 }
797} 869}
798 870
@@ -803,27 +875,27 @@ static void show_flag_status(void)
803 875
804 clear_line(); 876 clear_line();
805 putchar('_'); 877 putchar('_');
806 keypress = tless_getch(); 878 keypress = less_getch();
807 879
808 switch (keypress) { 880 switch (keypress) {
809 case 'M': 881 case 'M':
810 flag_val = option_mask32 & FLAG_M; 882 flag_val = option_mask32 & FLAG_M;
811 break; 883 break;
812 case 'm': 884 case 'm':
813 flag_val = option_mask32 & FLAG_m; 885 flag_val = option_mask32 & FLAG_m;
814 break; 886 break;
815 case '~': 887 case '~':
816 flag_val = option_mask32 & FLAG_TILDE; 888 flag_val = option_mask32 & FLAG_TILDE;
817 break; 889 break;
818 case 'N': 890 case 'N':
819 flag_val = option_mask32 & FLAG_N; 891 flag_val = option_mask32 & FLAG_N;
820 break; 892 break;
821 case 'E': 893 case 'E':
822 flag_val = option_mask32 & FLAG_E; 894 flag_val = option_mask32 & FLAG_E;
823 break; 895 break;
824 default: 896 default:
825 flag_val = 0; 897 flag_val = 0;
826 break; 898 break;
827 } 899 }
828 900
829 clear_line(); 901 clear_line();
@@ -831,15 +903,6 @@ static void show_flag_status(void)
831} 903}
832#endif 904#endif
833 905
834static void full_repaint(void)
835{
836 int temp_line_pos = line_pos;
837 data_readlines();
838 buffer_init();
839 buffer_line(temp_line_pos);
840}
841
842
843static void save_input_to_file(void) 906static void save_input_to_file(void)
844{ 907{
845 char *current_line; 908 char *current_line;
@@ -847,7 +910,7 @@ static void save_input_to_file(void)
847 FILE *fp; 910 FILE *fp;
848 911
849 print_statusline("Log file: "); 912 print_statusline("Log file: ");
850 current_line = tless_gets(sizeof("Log file: ")-1); 913 current_line = less_gets(sizeof("Log file: ")-1);
851 if (strlen(current_line) > 0) { 914 if (strlen(current_line) > 0) {
852 fp = fopen(current_line, "w"); 915 fp = fopen(current_line, "w");
853 free(current_line); 916 free(current_line);
@@ -855,7 +918,7 @@ static void save_input_to_file(void)
855 print_statusline("Error opening log file"); 918 print_statusline("Error opening log file");
856 return; 919 return;
857 } 920 }
858 for (i = 0; i < num_flines; i++) 921 for (i = 0; i < max_fline; i++)
859 fprintf(fp, "%s\n", flines[i]); 922 fprintf(fp, "%s\n", flines[i]);
860 fclose(fp); 923 fclose(fp);
861 buffer_print(); 924 buffer_print();
@@ -871,16 +934,15 @@ static void add_mark(void)
871 int letter; 934 int letter;
872 935
873 print_statusline("Mark: "); 936 print_statusline("Mark: ");
874 letter = tless_getch(); 937 letter = less_getch();
875 938
876 if (isalpha(letter)) { 939 if (isalpha(letter)) {
877
878 /* If we exceed 15 marks, start overwriting previous ones */ 940 /* If we exceed 15 marks, start overwriting previous ones */
879 if (num_marks == 14) 941 if (num_marks == 14)
880 num_marks = 0; 942 num_marks = 0;
881 943
882 mark_lines[num_marks][0] = letter; 944 mark_lines[num_marks][0] = letter;
883 mark_lines[num_marks][1] = line_pos; 945 mark_lines[num_marks][1] = cur_fline;
884 num_marks++; 946 num_marks++;
885 } else { 947 } else {
886 print_statusline("Invalid mark letter"); 948 print_statusline("Invalid mark letter");
@@ -893,7 +955,7 @@ static void goto_mark(void)
893 int i; 955 int i;
894 956
895 print_statusline("Go to mark: "); 957 print_statusline("Go to mark: ");
896 letter = tless_getch(); 958 letter = less_getch();
897 clear_line(); 959 clear_line();
898 960
899 if (isalpha(letter)) { 961 if (isalpha(letter)) {
@@ -915,17 +977,16 @@ static void goto_mark(void)
915static char opp_bracket(char bracket) 977static char opp_bracket(char bracket)
916{ 978{
917 switch (bracket) { 979 switch (bracket) {
918 case '{': case '[': 980 case '{': case '[':
919 return bracket + 2; 981 return bracket + 2;
920 case '(': 982 case '(':
921 return ')'; 983 return ')';
922 case '}': case ']': 984 case '}': case ']':
923 return bracket - 2; 985 return bracket - 2;
924 case ')': 986 case ')':
925 return '('; 987 return '(';
926 default:
927 return 0;
928 } 988 }
989 return 0;
929} 990}
930 991
931static void match_right_bracket(char bracket) 992static void match_right_bracket(char bracket)
@@ -933,11 +994,11 @@ static void match_right_bracket(char bracket)
933 int bracket_line = -1; 994 int bracket_line = -1;
934 int i; 995 int i;
935 996
936 if (strchr(flines[line_pos], bracket) == NULL) { 997 if (strchr(flines[cur_fline], bracket) == NULL) {
937 print_statusline("No bracket in top line"); 998 print_statusline("No bracket in top line");
938 return; 999 return;
939 } 1000 }
940 for (i = line_pos + 1; i < num_flines; i++) { 1001 for (i = cur_fline + 1; i < max_fline; i++) {
941 if (strchr(flines[i], opp_bracket(bracket)) != NULL) { 1002 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
942 bracket_line = i; 1003 bracket_line = i;
943 break; 1004 break;
@@ -945,7 +1006,7 @@ static void match_right_bracket(char bracket)
945 } 1006 }
946 if (bracket_line == -1) 1007 if (bracket_line == -1)
947 print_statusline("No matching bracket found"); 1008 print_statusline("No matching bracket found");
948 buffer_line(bracket_line - height + 2); 1009 buffer_line(bracket_line - max_displayed_line);
949} 1010}
950 1011
951static void match_left_bracket(char bracket) 1012static void match_left_bracket(char bracket)
@@ -953,12 +1014,12 @@ static void match_left_bracket(char bracket)
953 int bracket_line = -1; 1014 int bracket_line = -1;
954 int i; 1015 int i;
955 1016
956 if (strchr(flines[line_pos + height - 2], bracket) == NULL) { 1017 if (strchr(flines[cur_fline + max_displayed_line], bracket) == NULL) {
957 print_statusline("No bracket in bottom line"); 1018 print_statusline("No bracket in bottom line");
958 return; 1019 return;
959 } 1020 }
960 1021
961 for (i = line_pos + height - 2; i >= 0; i--) { 1022 for (i = cur_fline + max_displayed_line; i >= 0; i--) {
962 if (strchr(flines[i], opp_bracket(bracket)) != NULL) { 1023 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
963 bracket_line = i; 1024 bracket_line = i;
964 break; 1025 break;
@@ -974,105 +1035,104 @@ static void match_left_bracket(char bracket)
974static void keypress_process(int keypress) 1035static void keypress_process(int keypress)
975{ 1036{
976 switch (keypress) { 1037 switch (keypress) {
977 case KEY_DOWN: case 'e': case 'j': case 0x0d: 1038 case KEY_DOWN: case 'e': case 'j': case 0x0d:
978 buffer_down(1); 1039 buffer_down(1);
979 buffer_print(); 1040 buffer_print();
980 break; 1041 break;
981 case KEY_UP: case 'y': case 'k': 1042 case KEY_UP: case 'y': case 'k':
982 buffer_up(1); 1043 buffer_up(1);
983 buffer_print(); 1044 buffer_print();
984 break; 1045 break;
985 case PAGE_DOWN: case ' ': case 'z': 1046 case PAGE_DOWN: case ' ': case 'z':
986 buffer_down(height - 1); 1047 buffer_down(max_displayed_line + 1);
987 buffer_print(); 1048 buffer_print();
988 break; 1049 break;
989 case PAGE_UP: case 'w': case 'b': 1050 case PAGE_UP: case 'w': case 'b':
990 buffer_up(height - 1); 1051 buffer_up(max_displayed_line + 1);
991 buffer_print(); 1052 buffer_print();
992 break; 1053 break;
993 case 'd': 1054 case 'd':
994 buffer_down((height - 1) / 2); 1055 buffer_down((max_displayed_line + 1) / 2);
995 buffer_print(); 1056 buffer_print();
996 break; 1057 break;
997 case 'u': 1058 case 'u':
998 buffer_up((height - 1) / 2); 1059 buffer_up((max_displayed_line + 1) / 2);
999 buffer_print(); 1060 buffer_print();
1000 break; 1061 break;
1001 case KEY_HOME: case 'g': case 'p': case '<': case '%': 1062 case KEY_HOME: case 'g': case 'p': case '<': case '%':
1002 buffer_line(0); 1063 buffer_line(0);
1003 break; 1064 break;
1004 case KEY_END: case 'G': case '>': 1065 case KEY_END: case 'G': case '>':
1005 buffer_line(num_flines - height + 2); 1066 cur_fline = MAXLINES;
1006 break; 1067 read_lines();
1007 case 'q': case 'Q': 1068 buffer_line(cur_fline);
1008 tless_exit(0); 1069 break;
1009 break; 1070 case 'q': case 'Q':
1071 less_exit(0);
1072 break;
1010#if ENABLE_FEATURE_LESS_MARKS 1073#if ENABLE_FEATURE_LESS_MARKS
1011 case 'm': 1074 case 'm':
1012 add_mark(); 1075 add_mark();
1013 buffer_print(); 1076 buffer_print();
1014 break; 1077 break;
1015 case '\'': 1078 case '\'':
1016 goto_mark(); 1079 goto_mark();
1017 buffer_print(); 1080 buffer_print();
1018 break; 1081 break;
1019#endif 1082#endif
1020 case 'r': 1083 case 'r': case 'R':
1021 buffer_print(); 1084 buffer_print();
1022 break; 1085 break;
1023 case 'R': 1086 /*case 'R':
1024 full_repaint(); 1087 full_repaint();
1025 break; 1088 break;*/
1026 case 's': 1089 case 's':
1027 save_input_to_file(); 1090 save_input_to_file();
1028 break; 1091 break;
1029 case 'E': 1092 case 'E':
1030 examine_file(); 1093 examine_file();
1031 break; 1094 break;
1032#if ENABLE_FEATURE_LESS_FLAGS 1095#if ENABLE_FEATURE_LESS_FLAGS
1033 case '=': 1096 case '=':
1034 m_status_print(); 1097 m_status_print();
1035 break; 1098 break;
1036#endif 1099#endif
1037#if ENABLE_FEATURE_LESS_REGEXP 1100#if ENABLE_FEATURE_LESS_REGEXP
1038 case '/': 1101 case '/':
1039 option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS; 1102 option_mask32 &= ~LESS_STATE_MATCH_BACKWARDS;
1040 regex_process(); 1103 regex_process();
1041 break; 1104 break;
1042 case 'n': 1105 case 'n':
1043//printf("HERE 3\n");sleep(1); 1106 goto_match(match_pos + 1);
1044 goto_match(match_pos + 1); 1107 break;
1045 break; 1108 case 'N':
1046 case 'N': 1109 goto_match(match_pos - 1);
1047 goto_match(match_pos - 1); 1110 break;
1048 break; 1111 case '?':
1049 case '?': 1112 option_mask32 |= LESS_STATE_MATCH_BACKWARDS;
1050 option_mask32 |= LESS_STATE_MATCH_BACKWARDS; 1113 regex_process();
1051 regex_process(); 1114 break;
1052 break;
1053#endif 1115#endif
1054#if ENABLE_FEATURE_LESS_FLAGCS 1116#if ENABLE_FEATURE_LESS_FLAGCS
1055 case '-': 1117 case '-':
1056 flag_change(); 1118 flag_change();
1057 buffer_print(); 1119 buffer_print();
1058 break; 1120 break;
1059 case '_': 1121 case '_':
1060 show_flag_status(); 1122 show_flag_status();
1061 break; 1123 break;
1062#endif 1124#endif
1063#if ENABLE_FEATURE_LESS_BRACKETS 1125#if ENABLE_FEATURE_LESS_BRACKETS
1064 case '{': case '(': case '[': 1126 case '{': case '(': case '[':
1065 match_right_bracket(keypress); 1127 match_right_bracket(keypress);
1066 break; 1128 break;
1067 case '}': case ')': case ']': 1129 case '}': case ')': case ']':
1068 match_left_bracket(keypress); 1130 match_left_bracket(keypress);
1069 break; 1131 break;
1070#endif 1132#endif
1071 case ':': 1133 case ':':
1072 colon_process(); 1134 colon_process();
1073 break; 1135 break;
1074 default:
1075 break;
1076 } 1136 }
1077 1137
1078 if (isdigit(keypress)) 1138 if (isdigit(keypress))
@@ -1092,8 +1152,8 @@ int less_main(int argc, char **argv)
1092 getopt32(argc, argv, "EMmN~"); 1152 getopt32(argc, argv, "EMmN~");
1093 argc -= optind; 1153 argc -= optind;
1094 argv += optind; 1154 argv += optind;
1095 files = argv;
1096 num_files = argc; 1155 num_files = argc;
1156 files = argv;
1097 1157
1098 /* Another popular pager, most, detects when stdout 1158 /* Another popular pager, most, detects when stdout
1099 * is not a tty and turns into cat. This makes sense. */ 1159 * is not a tty and turns into cat. This makes sense. */
@@ -1109,33 +1169,35 @@ int less_main(int argc, char **argv)
1109 } else 1169 } else
1110 filename = xstrdup(files[0]); 1170 filename = xstrdup(files[0]);
1111 1171
1112 inp = xfopen(CURRENT_TTY, "r"); 1172 kbd_fd = xopen(CURRENT_TTY, O_RDONLY);
1113 1173
1114 get_terminal_width_height(fileno(inp), &width, &height); 1174 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1115 if (width < 10 || height < 3) 1175 /* 20: two tabstops + 4 */
1176 if (width < 20 || max_displayed_line < 3)
1116 bb_error_msg_and_die("too narrow here"); 1177 bb_error_msg_and_die("too narrow here");
1178 max_displayed_line -= 2;
1117 1179
1118 buffer = xmalloc(height * sizeof(char *)); 1180 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1119 if (option_mask32 & FLAG_TILDE) 1181 if (option_mask32 & FLAG_TILDE)
1120 empty_line_marker = ""; 1182 empty_line_marker = "";
1121 1183
1122 data_readlines(); 1184 tcgetattr(kbd_fd, &term_orig);
1123
1124 tcgetattr(fileno(inp), &term_orig);
1125 signal(SIGTERM, sig_catcher); 1185 signal(SIGTERM, sig_catcher);
1126 signal(SIGINT, sig_catcher); 1186 signal(SIGINT, sig_catcher);
1127 term_vi = term_orig; 1187 term_vi = term_orig;
1128 term_vi.c_lflag &= (~ICANON & ~ECHO); 1188 term_vi.c_lflag &= ~(ICANON | ECHO);
1129 term_vi.c_iflag &= (~IXON & ~ICRNL); 1189 term_vi.c_iflag &= ~(IXON | ICRNL);
1130 term_vi.c_oflag &= (~ONLCR); 1190 /*term_vi.c_oflag &= ~ONLCR;*/
1131 term_vi.c_cc[VMIN] = 1; 1191 term_vi.c_cc[VMIN] = 1;
1132 term_vi.c_cc[VTIME] = 0; 1192 term_vi.c_cc[VTIME] = 0;
1133 1193
1134 buffer_init(); 1194 /* Want to do it just once, but it doesn't work, */
1135 buffer_print(); 1195 /* so we are redoing it (see code above). Mystery... */
1196 /*tcsetattr(kbd_fd, TCSANOW, &term_vi);*/
1136 1197
1198 reinitialize();
1137 while (1) { 1199 while (1) {
1138 keypress = tless_getch(); 1200 keypress = less_getch();
1139 keypress_process(keypress); 1201 keypress_process(keypress);
1140 } 1202 }
1141} 1203}