blob: 3fd22ca19a69cb965c4f6a02ebd6df0659001713 [file] [log] [blame]
Rob Landley9200e792005-09-15 19:26:59 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Mini less implementation for busybox
4 *
5 *
6 * Copyright (C) 2005 by Rob Sullivan <cogito.ergo.cogito@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 *
23 * This program needs a lot of development, so consider it in a beta stage
24 * at best.
25 *
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000026 * TODO:
Rob Landley9200e792005-09-15 19:26:59 +000027 * - Add more regular expression support - search modifiers, certain matches, etc.
28 * - Add more complex bracket searching - currently, nested brackets are
29 * not considered.
30 * - Add support for "F" as an input. This causes less to act in
31 * a similar way to tail -f.
32 * - Check for binary files, and prompt the user if a binary file
33 * is detected.
34 * - Allow horizontal scrolling. Currently, lines simply continue onto
35 * the next line, per the terminal's discretion
36 *
37 * Notes:
38 * - filename is an array and not a pointer because that avoids all sorts
39 * of complications involving the fact that something that is pointed to
40 * will be changed if the pointer is changed.
41 * - the inp file pointer is used so that keyboard input works after
42 * redirected input has been read from stdin
43*/
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <termios.h>
49#include <unistd.h>
Rob Landley9200e792005-09-15 19:26:59 +000050#include <ctype.h>
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000051
Rob Landley9200e792005-09-15 19:26:59 +000052#include "busybox.h"
53
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000054#ifdef CONFIG_FEATURE_LESS_REGEXP
55#include "xregex.h"
56#endif
57
58
Rob Landley9200e792005-09-15 19:26:59 +000059/* These are the escape sequences corresponding to special keys */
60#define REAL_KEY_UP 'A'
61#define REAL_KEY_DOWN 'B'
62#define REAL_KEY_RIGHT 'C'
63#define REAL_KEY_LEFT 'D'
64#define REAL_PAGE_UP '5'
65#define REAL_PAGE_DOWN '6'
66
67/* These are the special codes assigned by this program to the special keys */
68#define PAGE_UP 20
69#define PAGE_DOWN 21
70#define KEY_UP 22
71#define KEY_DOWN 23
72#define KEY_RIGHT 24
73#define KEY_LEFT 25
74
75/* The escape codes for highlighted and normal text */
76#define HIGHLIGHT "\033[7m"
77#define NORMAL "\033[0m"
78
79/* The escape code to clear the screen */
80#define CLEAR "\033[2J"
81
82/* Maximum number of lines in a file */
83#define MAXLINES 10000
84
85/* Get height and width of terminal */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000086#define tty_width_height() get_terminal_width_height(0, &width, &height)
Rob Landley9200e792005-09-15 19:26:59 +000087
88static int height;
89static int width;
90static char **files;
91static char filename[256];
Rob Landleyd57ae8b2005-09-18 00:58:49 +000092static char **buffer;
93static char **flines;
Rob Landley9200e792005-09-15 19:26:59 +000094static int current_file = 1;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000095static int line_pos;
Rob Landley9200e792005-09-15 19:26:59 +000096static int num_flines;
97static int num_files = 1;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +000098static int past_eof;
Rob Landley9200e792005-09-15 19:26:59 +000099
100/* Command line options */
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000101static unsigned long flags;
102#define FLAG_E 1
103#define FLAG_M (1<<1)
104#define FLAG_m (1<<2)
105#define FLAG_N (1<<3)
106#define FLAG_TILDE (1<<4)
Rob Landley9200e792005-09-15 19:26:59 +0000107
108/* This is needed so that program behaviour changes when input comes from
109 stdin */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000110static int inp_stdin;
Rob Landley9200e792005-09-15 19:26:59 +0000111/* This is required so that when a file is requested to be examined after
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000112 input has come from stdin (e.g. dmesg | less), the input stream from
Rob Landley9200e792005-09-15 19:26:59 +0000113 the keyboard still stays the same. If it switched back to stdin, keyboard
114 input wouldn't work. */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000115static int ea_inp_stdin;
Rob Landley9200e792005-09-15 19:26:59 +0000116
117#ifdef CONFIG_FEATURE_LESS_MARKS
118static int mark_lines[15][2];
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000119static int num_marks;
Rob Landley9200e792005-09-15 19:26:59 +0000120#endif
121
122#ifdef CONFIG_FEATURE_LESS_REGEXP
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000123static int match_found;
Rob Landley9200e792005-09-15 19:26:59 +0000124static int match_lines[100];
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000125static int match_pos;
126static int num_matches;
127static int match_backwards;
Rob Landley9200e792005-09-15 19:26:59 +0000128static int num_back_match = 1;
129#endif
130
131/* Needed termios structures */
132static struct termios term_orig, term_vi;
133
134/* File pointer to get input from */
135static FILE *inp;
136
137/* Reset terminal input to normal */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000138static void set_tty_cooked(void) {
139 fflush(stdout);
140 tcsetattr(0, TCSANOW, &term_orig);
Rob Landley9200e792005-09-15 19:26:59 +0000141}
142
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000143/* Set terminal input to raw mode (taken from vi.c) */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000144static void set_tty_raw(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000145 tcgetattr(0, &term_orig);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000146 term_vi = term_orig;
147 term_vi.c_lflag &= (~ICANON & ~ECHO);
148 term_vi.c_iflag &= (~IXON & ~ICRNL);
149 term_vi.c_oflag &= (~ONLCR);
150 term_vi.c_cc[VMIN] = 1;
151 term_vi.c_cc[VTIME] = 0;
152 tcsetattr(0, TCSANOW, &term_vi);
Rob Landley9200e792005-09-15 19:26:59 +0000153}
154
155/* Exit the program gracefully */
156static void tless_exit(int code) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000157
Rob Landley9200e792005-09-15 19:26:59 +0000158 /* TODO: We really should save the terminal state when we start,
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000159 and restore it when we exit. Less does this with the
Rob Landley9200e792005-09-15 19:26:59 +0000160 "ti" and "te" termcap commands; can this be done with
161 only termios.h? */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000162
Rob Landley9200e792005-09-15 19:26:59 +0000163 putchar('\n');
164 exit(code);
165}
166
167/* Grab a character from input without requiring the return key. If the
168 character is ASCII \033, get more characters and assign certain sequences
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000169 special return codes. Note that this function works best with raw input. */
170static int tless_getch(void) {
171
Rob Landley9200e792005-09-15 19:26:59 +0000172 set_tty_raw();
173 char input_key[3];
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000174
Rob Landley9200e792005-09-15 19:26:59 +0000175 input_key[0] = getc(inp);
176 /* Detect escape sequences (i.e. arrow keys) and handle
177 them accordingly */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000178
Rob Landley9200e792005-09-15 19:26:59 +0000179 if (input_key[0] == '\033') {
180 input_key[1] = getc(inp);
181 input_key[2] = getc(inp);
182 set_tty_cooked();
183 if (input_key[1] == '[') {
184 if (input_key[2] == REAL_KEY_UP)
185 return KEY_UP;
186 else if (input_key[2] == REAL_KEY_DOWN)
187 return KEY_DOWN;
188 else if (input_key[2] == REAL_KEY_RIGHT)
189 return KEY_RIGHT;
190 else if (input_key[2] == REAL_KEY_LEFT)
191 return KEY_LEFT;
192 else if (input_key[2] == REAL_PAGE_UP)
193 return PAGE_UP;
194 else if (input_key[2] == REAL_PAGE_DOWN)
195 return PAGE_DOWN;
196 }
197 }
198 /* The input is a normal ASCII value */
199 else {
200 set_tty_cooked();
201 return input_key[0];
202 }
203 return 0;
204}
205
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000206/* Move the cursor to a position (x,y), where (0,0) is the
Rob Landley9200e792005-09-15 19:26:59 +0000207 top-left corner of the console */
208static void move_cursor(int x, int y) {
209 printf("\033[%i;%iH", x, y);
210}
211
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000212static void clear_line(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000213 move_cursor(height, 0);
214 printf("\033[K");
215}
216
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000217/* This adds line numbers to every line, as the -N flag necessitates */
218static void add_linenumbers(void) {
219
220 char current_line[256];
221 int i;
222
223 for (i = 0; i <= num_flines; i++) {
224 safe_strncpy(current_line, flines[i], 256);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000225 flines[i] = xrealloc(flines[i], strlen(current_line) + 7);
226 sprintf(flines[i],"%5d %s", i + 1, current_line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000227 }
228}
229
230static void data_readlines(void) {
231
Rob Landley9200e792005-09-15 19:26:59 +0000232 int i;
233 char current_line[256];
234 FILE *fp;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000235
Rob Landley9200e792005-09-15 19:26:59 +0000236 fp = (inp_stdin) ? stdin : bb_xfopen(filename, "rt");
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000237
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000238 /* First of all, we need to know the number of lines so that flines can be initialised. */
239 for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++)
240 fgets(current_line, 256, fp);
241 rewind(fp);
242 /* Initialise fp */
243 flines = malloc(i * sizeof(char *));
244
Rob Landley9200e792005-09-15 19:26:59 +0000245 for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++) {
246 strcpy(current_line, "");
247 fgets(current_line, 256, fp);
248 bb_xferror(fp, filename);
249 flines[i] = (char *) bb_xstrndup(current_line, (strlen(current_line) + 1) * sizeof(char));
250 }
251 num_flines = i - 2;
252
253/* Reset variables for a new file */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000254
Rob Landley9200e792005-09-15 19:26:59 +0000255 line_pos = 0;
256 past_eof = 0;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000257
Rob Landley9200e792005-09-15 19:26:59 +0000258 fclose(fp);
259
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000260 inp = (inp_stdin) ? fopen(CURRENT_TTY, "r") : stdin;
261
Rob Landley9200e792005-09-15 19:26:59 +0000262 if (ea_inp_stdin) {
263 fclose(inp);
264 inp = fopen(CURRENT_TTY, "r");
265 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000266
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000267 if (flags & FLAG_N)
Rob Landley9200e792005-09-15 19:26:59 +0000268 add_linenumbers();
269}
270
Rob Landley9200e792005-09-15 19:26:59 +0000271/* Turn a percentage into a line number */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000272static int reverse_percent(int percentage) {
Rob Landley9200e792005-09-15 19:26:59 +0000273 double linenum = percentage;
274 linenum = ((linenum / 100) * num_flines) - 1;
275 return(linenum);
276}
277
278#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000279
280/* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes
281 * on my build. */
282static int calc_percent(void) {
283 return ((100 * (line_pos + height - 2) / num_flines) + 1);
284}
285
Rob Landley9200e792005-09-15 19:26:59 +0000286/* Print a status line if -M was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000287static void m_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000288
289 int percentage;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000290
Rob Landley9200e792005-09-15 19:26:59 +0000291 if (!past_eof) {
292 if (!line_pos) {
293 if (num_files > 1)
294 printf("%s%s %s%i%s%i%s%i-%i/%i ", HIGHLIGHT, filename, "(file ", current_file, " of ", num_files, ") lines ", line_pos + 1, line_pos + height - 1, num_flines + 1);
295 else {
296 printf("%s%s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
297 }
298 }
299 else {
300 printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
301 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000302
Rob Landley9200e792005-09-15 19:26:59 +0000303 if (line_pos == num_flines - height + 2) {
304 printf("(END) %s", NORMAL);
305 if ((num_files > 1) && (current_file != num_files))
306 printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL);
307 }
308 else {
309 percentage = calc_percent();
310 printf("%i%s %s", percentage, "%", NORMAL);
311 }
312 }
313 else {
314 printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, line_pos + 1, num_flines + 1, num_flines + 1);
315 if ((num_files > 1) && (current_file != num_files))
316 printf("- Next: %s", files[current_file]);
317 printf("%s", NORMAL);
318 }
319}
320
321/* Print a status line if -m was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000322static void medium_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000323
324 int percentage;
325 percentage = calc_percent();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000326
Rob Landley9200e792005-09-15 19:26:59 +0000327 if (!line_pos)
328 printf("%s%s %i%s%s", HIGHLIGHT, filename, percentage, "%", NORMAL);
329 else if (line_pos == num_flines - height + 2)
330 printf("%s(END)%s", HIGHLIGHT, NORMAL);
331 else
332 printf("%s%i%s%s", HIGHLIGHT, percentage, "%", NORMAL);
333}
334#endif
335
336/* Print the status line */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000337static void status_print(void) {
338
Rob Landley9200e792005-09-15 19:26:59 +0000339 /* Change the status if flags have been set */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000340#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000341 if (flags & FLAG_M)
Rob Landley9200e792005-09-15 19:26:59 +0000342 m_status_print();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000343 else if (flags & FLAG_m)
Rob Landley9200e792005-09-15 19:26:59 +0000344 medium_status_print();
345 /* No flags set */
346 else {
347#endif
348 if (!line_pos) {
349 printf("%s%s %s", HIGHLIGHT, filename, NORMAL);
350 if (num_files > 1)
351 printf("%s%s%i%s%i%s%s", HIGHLIGHT, "(file ", current_file, " of ", num_files, ")", NORMAL);
352 }
353 else if (line_pos == num_flines - height + 2) {
354 printf("%s%s %s", HIGHLIGHT, "(END)", NORMAL);
355 if ((num_files > 1) && (current_file != num_files))
356 printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL);
357 }
358 else {
359 printf("%c", ':');
360 }
361#ifdef CONFIG_FEATURE_LESS_FLAGS
362 }
363#endif
364}
365
366/* Print the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000367static void buffer_print(void) {
368
Rob Landley9200e792005-09-15 19:26:59 +0000369 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000370
Rob Landley9200e792005-09-15 19:26:59 +0000371 if (num_flines >= height - 2) {
372 printf("%s", CLEAR);
373 move_cursor(0,0);
374 for (i = 0; i < height - 1; i++)
375 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000376 }
377 else {
378 printf("%s", CLEAR);
379 move_cursor(0,0);
380 for (i = 1; i < (height - 1 - num_flines); i++)
381 putchar('\n');
382 for (i = 0; i < height - 1; i++)
383 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000384 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000385
386 status_print();
Rob Landley9200e792005-09-15 19:26:59 +0000387}
388
389/* Initialise the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000390static void buffer_init(void) {
391
Rob Landley9200e792005-09-15 19:26:59 +0000392 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000393
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000394 /* malloc the number of lines needed for the buffer */
395 buffer = xrealloc(buffer, height * sizeof(char *));
396
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000397 /* Fill the buffer until the end of the file or the
Rob Landley9200e792005-09-15 19:26:59 +0000398 end of the buffer is reached */
399 for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000400 buffer[i] = (char *) bb_xstrdup(flines[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000401 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000402
Rob Landley9200e792005-09-15 19:26:59 +0000403 /* If the buffer still isn't full, fill it with blank lines */
404 for (; i < (height - 1); i++) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000405 buffer[i] = "";
Rob Landley9200e792005-09-15 19:26:59 +0000406 }
407}
408
409/* Move the buffer up and down in the file in order to scroll */
410static void buffer_down(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000411
Rob Landley9200e792005-09-15 19:26:59 +0000412 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000413
Rob Landley9200e792005-09-15 19:26:59 +0000414 if (!past_eof) {
415 if (line_pos + (height - 3) + nlines < num_flines) {
416 line_pos += nlines;
417 for (i = 0; i < (height - 1); i++)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000418 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000419 }
420 else {
421 /* As the number of lines requested was too large, we just move
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000422 to the end of the file */
423 while (line_pos + (height - 3) + 1 < num_flines) {
Rob Landley9200e792005-09-15 19:26:59 +0000424 line_pos += 1;
425 for (i = 0; i < (height - 1); i++)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000426 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000427 }
428 }
429
430 /* We exit if the -E flag has been set */
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000431 if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines))
Rob Landley9200e792005-09-15 19:26:59 +0000432 tless_exit(0);
433 }
434}
435
436static void buffer_up(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000437
Rob Landley9200e792005-09-15 19:26:59 +0000438 int i;
439 int tilde_line;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000440
Rob Landley9200e792005-09-15 19:26:59 +0000441 if (!past_eof) {
442 if (line_pos - nlines >= 0) {
443 line_pos -= nlines;
444 for (i = 0; i < (height - 1); i++)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000445 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000446 }
447 else {
448 /* As the requested number of lines to move was too large, we
449 move one line up at a time until we can't. */
450 while (line_pos != 0) {
451 line_pos -= 1;
452 for (i = 0; i < (height - 1); i++)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000453 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000454 }
455 }
456 }
457 else {
458 /* Work out where the tildes start */
459 tilde_line = num_flines - line_pos + 3;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000460
Rob Landley9200e792005-09-15 19:26:59 +0000461 line_pos -= nlines;
462 /* Going backwards nlines lines has taken us to a point where
463 nothing is past the EOF, so we revert to normal. */
464 if (line_pos < num_flines - height + 3) {
465 past_eof = 0;
466 buffer_up(nlines);
467 }
468 else {
469 /* We only move part of the buffer, as the rest
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000470 is past the EOF */
Rob Landley9200e792005-09-15 19:26:59 +0000471 for (i = 0; i < (height - 1); i++) {
472 if (i < tilde_line - nlines + 1)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000473 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000474 else {
475 if (line_pos >= num_flines - height + 2)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000476 buffer[i] = "~\n";
Rob Landley9200e792005-09-15 19:26:59 +0000477 }
478 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000479 }
Rob Landley9200e792005-09-15 19:26:59 +0000480 }
481}
482
483static void buffer_line(int linenum) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000484
Rob Landley9200e792005-09-15 19:26:59 +0000485 int i;
486
487 past_eof = 0;
488
489 if (linenum < 1 || linenum > num_flines) {
490 clear_line();
491 printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum, NORMAL);
492 }
493 else if (linenum < (num_flines - height - 2)) {
494 for (i = 0; i < (height - 1); i++)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000495 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000496 line_pos = linenum;
497 }
498 else {
499 for (i = 0; i < (height - 1); i++) {
500 if (linenum + i < num_flines + 2)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000501 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000502 else
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000503 buffer[i] = (char *) bb_xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n");
Rob Landley9200e792005-09-15 19:26:59 +0000504 }
505 line_pos = linenum;
506 /* Set past_eof so buffer_down and buffer_up act differently */
507 past_eof = 1;
508 }
509}
510
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000511/* Reinitialise everything for a new file - free the memory and start over */
512static void reinitialise(void) {
513
514 int i;
515
516 for (i = 0; i <= num_flines; i++)
517 free(flines[i]);
518 free(flines);
519
520 data_readlines();
521 buffer_init();
522 buffer_print();
523}
524
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000525static void examine_file(void) {
526
527 int newline_offset;
528
529 clear_line();
530 printf("Examine: ");
531 fgets(filename, 256, inp);
532
533 /* As fgets adds a newline to the end of an input string, we
534 need to remove it */
535 newline_offset = strlen(filename) - 1;
536 filename[newline_offset] = '\0';
537
538 files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
539 current_file = num_files + 1;
540 num_files++;
541
542 inp_stdin = 0;
543 ea_inp_stdin = 1;
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000544 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000545}
546
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000547/* This function changes the file currently being paged. direction can be one of the following:
548 * -1: go back one file
549 * 0: go to the first file
550 * 1: go forward one file
551*/
552static void change_file (int direction) {
553 if (current_file != ((direction > 0) ? num_files : 1)) {
554 current_file = direction ? current_file + direction : 1;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000555 strcpy(filename, files[current_file - 1]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000556 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000557 }
558 else {
559 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000560 printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000561 }
562}
563
564static void remove_current_file(void) {
565
566 int i;
567
568 if (current_file != 1) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000569 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000570 for (i = 3; i <= num_files; i++)
571 files[i - 2] = files[i - 1];
572 num_files--;
573 buffer_print();
574 }
575 else {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000576 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000577 for (i = 2; i <= num_files; i++)
578 files[i - 2] = files[i - 1];
579 num_files--;
580 current_file--;
581 buffer_print();
582 }
583}
584
585static void colon_process(void) {
586
587 int keypress;
588
589 /* Clear the current line and print a prompt */
590 clear_line();
591 printf(" :");
592
593 keypress = tless_getch();
594 switch (keypress) {
595 case 'd':
596 remove_current_file();
597 break;
598 case 'e':
599 examine_file();
600 break;
601#ifdef CONFIG_FEATURE_LESS_FLAGS
602 case 'f':
603 clear_line();
604 m_status_print();
605 break;
606#endif
607 case 'n':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000608 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000609 break;
610 case 'p':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000611 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000612 break;
613 case 'q':
614 tless_exit(0);
615 break;
616 case 'x':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000617 change_file(0);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000618 break;
619 default:
620 break;
621 }
622}
623
624#ifdef CONFIG_FEATURE_LESS_REGEXP
625/* The below two regular expression handler functions NEED development. */
626
627/* Get a regular expression from the user, and then go through the current
628 file line by line, running a processing regex function on each one. */
629
630static char *insert_highlights (char *line, int start, int end) {
631
632 char *new_line = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 10);
633
634 memset(new_line, 0, ((sizeof(char) * (strlen(line) + 1)) + 10));
635 strncat(new_line, line, start);
636 strcat(new_line, HIGHLIGHT);
637 strncat(new_line, line + start, end - start);
638 strcat(new_line, NORMAL);
639 strncat(new_line, line + end, strlen(line) - end);
640
641 return new_line;
642}
643
644static char *process_regex_on_line(char *line, regex_t *pattern) {
645 /* This function takes the regex and applies it to the line.
646 Each part of the line that matches has the HIGHLIGHT
647 and NORMAL escape sequences placed around it by
648 insert_highlights, and then the line is returned. */
649
650 int match_status;
651 char *line2 = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 64);
652 char sub_line[256];
653 int prev_eo = 0;
"Vladimir N. Oleynik"8d3c40d2005-09-16 13:16:01 +0000654 regmatch_t match_structs;
655
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000656 memset(sub_line, 0, 256);
657 strcpy(line2, line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000658
659 match_found = 0;
660 match_status = regexec(pattern, line2, 1, &match_structs, 0);
661
662 while (match_status == 0) {
663
664 memset(sub_line, 0, 256);
665
666 if (match_found == 0)
667 match_found = 1;
668
669 line2 = insert_highlights(line2, match_structs.rm_so + prev_eo, match_structs.rm_eo + prev_eo);
670 if (match_structs.rm_eo + 11 + prev_eo < strlen(line2))
671 strcat(sub_line, line2 + match_structs.rm_eo + 11 + prev_eo);
672
673 prev_eo += match_structs.rm_eo + 11;
674 match_status = regexec(pattern, sub_line, 1, &match_structs, REG_NOTBOL);
675 }
676
677 return line2;
678}
679
680static void regex_process(void) {
681
682 char uncomp_regex[100];
683 char current_line[256];
684 int i;
685 int j = 0;
686 regex_t *pattern;
687
688 /* Reset variables */
689 match_lines[0] = -1;
690 match_pos = 0;
691 num_matches = 0;
692 match_found = 0;
693
694 pattern = (regex_t *) malloc(sizeof(regex_t));
695 memset(pattern, 0, sizeof(regex_t));
696
697 /* Get the uncompiled regular expression from the user */
698 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000699 putchar((match_backwards) ? '?' : '/');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000700 scanf("%s", uncomp_regex);
701
702 /* Compile the regex and check for errors */
703 xregcomp(pattern, uncomp_regex, 0);
704
705 /* Run the regex on each line of the current file here */
706 for (i = 0; i <= num_flines; i++) {
707 strcpy(current_line, process_regex_on_line(flines[i], pattern));
708 flines[i] = (char *) bb_xstrndup(current_line, sizeof(char) * (strlen(current_line)+1));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000709 if (match_found) {
710 match_lines[j] = i;
711 j++;
712 }
713 }
714
715 num_matches = j;
716
717 if ((match_lines[0] != -1) && (num_flines > height - 2))
718 buffer_line(match_lines[0]);
719 else
720 buffer_init();
721}
722
723static void goto_match(int match) {
724
725 /* This goes to a specific match - all line positions of matches are
726 stored within the match_lines[] array. */
727 if ((match < num_matches) && (match >= 0)) {
728 buffer_line(match_lines[match]);
729 match_pos = match;
730 }
731}
732
733static void search_backwards(void) {
734
735 int current_linepos = line_pos;
736 int i;
737
738 match_backwards = 1;
739 regex_process();
740
741 for (i = 0; i < num_matches; i++) {
742 if (match_lines[i] > current_linepos) {
743 buffer_line(match_lines[i - num_back_match]);
744 break;
745 }
746 }
747
748 /* Reset variables */
749 match_backwards = 0;
750 num_back_match = 1;
751
752}
753#endif
754
755static void number_process(int first_digit) {
756
757 int i = 1;
758 int num;
759 char num_input[80];
760 char keypress;
761 num_input[0] = first_digit;
762
763 /* Clear the current line, print a prompt, and then print the digit */
764 clear_line();
765 printf(":%c", first_digit);
766
767 /* Receive input until a letter is given */
768 while((num_input[i] = tless_getch()) && isdigit(num_input[i])) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000769 printf("%c", num_input[i]);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000770 i++;
771 }
772
773 /* Take the final letter out of the digits string */
774 keypress = num_input[i];
775 num_input[i] = '\0';
776 i--;
777 num = atoi(num_input);
778
779 /* We now know the number and the letter entered, so we process them */
780 switch (keypress) {
781 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
782 buffer_down(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000783 break;
784 case KEY_UP: case 'b': case 'w': case 'y': case 'u':
785 buffer_up(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000786 break;
787 case 'g': case '<': case 'G': case '>':
788 if (num_flines >= height - 2)
789 buffer_line(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000790 break;
791 case 'p': case '%':
792 buffer_line(reverse_percent(num));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000793 break;
794#ifdef CONFIG_FEATURE_LESS_REGEXP
795 case 'n':
796 goto_match(match_pos + num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000797 break;
798 case '/':
799 regex_process();
800 goto_match(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000801 break;
802 case '?':
803 num_back_match = num;
804 search_backwards();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000805 break;
806#endif
807 default:
808 break;
809 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000810
811 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000812}
813
814#ifdef CONFIG_FEATURE_LESS_FLAGCS
815static void flag_change(void) {
816
817 int keypress;
818
819 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000820 putchar('-');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000821 keypress = tless_getch();
822
823 switch (keypress) {
824 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000825 flags &= ~FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000826 break;
827 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000828 flags &= ~FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000829 break;
830 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000831 flags &= ~FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000832 break;
833 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000834 flags &= ~FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000835 break;
836 default:
837 break;
838 }
839}
840
841static void show_flag_status(void) {
842
843 int keypress;
844 int flag_val;
845
846 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000847 putchar('_');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000848 keypress = tless_getch();
849
850 switch (keypress) {
851 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000852 flag_val = flags & FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000853 break;
854 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000855 flag_val = flags & FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000856 break;
857 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000858 flag_val = flags & FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000859 break;
860 case 'N':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000861 flag_val = flags & FLAG_N;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000862 break;
863 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000864 flag_val = flags & FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000865 break;
866 default:
867 flag_val = 0;
868 break;
869 }
870
871 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000872 printf("%s%s%i%s", HIGHLIGHT, "The status of the flag is: ", flag_val, NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000873}
874#endif
875
876static void full_repaint(void) {
877
878 int temp_line_pos = line_pos;
879 data_readlines();
880 buffer_init();
881 buffer_line(temp_line_pos);
882 buffer_print();
883}
884
885
886static void save_input_to_file(void) {
887
888 char current_line[256];
889 int i;
890 FILE *fp;
891
892 clear_line();
893 printf("Log file: ");
894 fgets(current_line, 256, inp);
895 current_line[strlen(current_line) - 1] = '\0';
896 if (strlen(current_line)) {
897 fp = bb_xfopen(current_line, "w");
898 for (i = 0; i < num_flines; i++)
899 fprintf(fp, "%s", flines[i]);
900 fclose(fp);
901 buffer_print();
902 }
903 else
904 printf("%sNo log file%s", HIGHLIGHT, NORMAL);
905}
906
907#ifdef CONFIG_FEATURE_LESS_MARKS
908static void add_mark(void) {
909
910 int letter;
911 int mark_line;
912
913 clear_line();
914 printf("Mark: ");
915 letter = tless_getch();
916
917 if (isalpha(letter)) {
918 mark_line = line_pos;
919
920 /* If we exceed 15 marks, start overwriting previous ones */
921 if (num_marks == 14)
922 num_marks = 0;
923
924 mark_lines[num_marks][0] = letter;
925 mark_lines[num_marks][1] = line_pos;
926 num_marks++;
927 }
928 else {
929 clear_line();
930 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
931 }
932}
933
934static void goto_mark(void) {
935
936 int letter;
937 int i;
938
939 clear_line();
940 printf("Go to mark: ");
941 letter = tless_getch();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000942 clear_line();
943
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000944 if (isalpha(letter)) {
945 for (i = 0; i <= num_marks; i++)
946 if (letter == mark_lines[i][0]) {
947 buffer_line(mark_lines[i][1]);
948 break;
949 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000950 if ((num_marks == 14) && (letter != mark_lines[14][0]))
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000951 printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000952 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000953 else
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000954 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000955}
956#endif
957
958
959#ifdef CONFIG_FEATURE_LESS_BRACKETS
960
961static char opp_bracket (char bracket) {
962
963 switch (bracket) {
964 case '{': case '[':
965 return bracket + 2;
966 break;
967 case '(':
968 return ')';
969 break;
970 case '}': case ']':
971 return bracket - 2;
972 break;
973 case ')':
974 return '(';
975 break;
976 default:
977 return 0;
978 break;
979 }
980}
981
982static void match_right_bracket(char bracket) {
983
984 int bracket_line = -1;
985 int i;
986
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000987 clear_line();
988
989 if (strchr(flines[line_pos], bracket) == NULL)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000990 printf("%s%s%s", HIGHLIGHT, "No bracket in top line", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000991 else {
992 for (i = line_pos + 1; i < num_flines; i++) {
993 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
994 bracket_line = i;
995 break;
996 }
997 }
998
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000999 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001000 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001001
1002 buffer_line(bracket_line - height + 2);
1003 buffer_print();
1004 }
1005}
1006
1007static void match_left_bracket (char bracket) {
1008
1009 int bracket_line = -1;
1010 int i;
1011
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001012 clear_line();
1013
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001014 if (strchr(flines[line_pos + height - 2], bracket) == NULL) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001015 printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL);
1016 printf("%s", flines[line_pos + height]);
1017 sleep(4);
1018 }
1019 else {
1020 for (i = line_pos + height - 2; i >= 0; i--) {
1021 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
1022 bracket_line = i;
1023 break;
1024 }
1025 }
1026
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001027 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001028 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001029
1030 buffer_line(bracket_line);
1031 buffer_print();
1032 }
1033}
1034
1035#endif /* CONFIG_FEATURE_LESS_BRACKETS */
1036
Rob Landley9200e792005-09-15 19:26:59 +00001037static void keypress_process(int keypress) {
1038 switch (keypress) {
1039 case KEY_DOWN: case 'e': case 'j': case '\015':
1040 buffer_down(1);
1041 buffer_print();
1042 break;
1043 case KEY_UP: case 'y': case 'k':
1044 buffer_up(1);
1045 buffer_print();
1046 break;
1047 case PAGE_DOWN: case ' ': case 'z':
1048 buffer_down(height - 1);
1049 buffer_print();
1050 break;
1051 case PAGE_UP: case 'w': case 'b':
1052 buffer_up(height - 1);
1053 buffer_print();
1054 break;
1055 case 'd':
1056 buffer_down((height - 1) / 2);
1057 buffer_print();
1058 break;
1059 case 'u':
1060 buffer_up((height - 1) / 2);
1061 buffer_print();
1062 break;
1063 case 'g': case 'p': case '<': case '%':
1064 buffer_up(num_flines + 1);
1065 buffer_print();
1066 break;
1067 case 'G': case '>':
1068 buffer_down(num_flines + 1);
1069 buffer_print();
1070 break;
1071 case 'q': case 'Q':
1072 tless_exit(0);
1073 break;
1074#ifdef CONFIG_FEATURE_LESS_MARKS
1075 case 'm':
1076 add_mark();
1077 buffer_print();
1078 break;
1079 case '\'':
1080 goto_mark();
1081 buffer_print();
1082 break;
1083#endif
1084 case 'r':
1085 buffer_print();
1086 break;
1087 case 'R':
1088 full_repaint();
1089 break;
1090 case 's':
1091 if (inp_stdin)
1092 save_input_to_file();
1093 break;
1094 case 'E':
1095 examine_file();
1096 break;
1097#ifdef CONFIG_FEATURE_LESS_FLAGS
1098 case '=':
1099 clear_line();
1100 m_status_print();
1101 break;
1102#endif
1103#ifdef CONFIG_FEATURE_LESS_REGEXP
1104 case '/':
1105 regex_process();
1106 buffer_print();
1107 break;
1108 case 'n':
1109 goto_match(match_pos + 1);
1110 buffer_print();
1111 break;
1112 case 'N':
1113 goto_match(match_pos - 1);
1114 buffer_print();
1115 break;
1116 case '?':
1117 search_backwards();
1118 buffer_print();
1119 break;
1120#endif
1121#ifdef CONFIG_FEATURE_LESS_FLAGCS
1122 case '-':
1123 flag_change();
1124 buffer_print();
1125 break;
1126 case '_':
1127 show_flag_status();
1128 break;
1129#endif
1130#ifdef CONFIG_FEATURE_LESS_BRACKETS
1131 case '{': case '(': case '[':
1132 match_right_bracket(keypress);
1133 break;
1134 case '}': case ')': case ']':
1135 match_left_bracket(keypress);
1136 break;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001137#endif
1138 case ':':
Rob Landley9200e792005-09-15 19:26:59 +00001139 colon_process();
1140 break;
1141 default:
1142 break;
1143 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001144
Rob Landley9200e792005-09-15 19:26:59 +00001145 if (isdigit(keypress))
1146 number_process(keypress);
1147}
1148
Rob Landley9200e792005-09-15 19:26:59 +00001149int less_main(int argc, char **argv) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001150
Rob Landley9200e792005-09-15 19:26:59 +00001151 int keypress;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001152
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001153 flags = bb_getopt_ulflags(argc, argv, "EMmN~");
Rob Landley9200e792005-09-15 19:26:59 +00001154
1155 argc -= optind;
1156 argv += optind;
1157 files = argv;
1158 num_files = argc;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001159
Rob Landley9200e792005-09-15 19:26:59 +00001160 if (!num_files) {
1161 if (ttyname(STDIN_FILENO) == NULL)
1162 inp_stdin = 1;
1163 else {
1164 bb_error_msg("Missing filename");
1165 bb_show_usage();
1166 }
1167 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001168
Rob Landley9200e792005-09-15 19:26:59 +00001169 strcpy(filename, (inp_stdin) ? "stdin" : files[0]);
1170 tty_width_height();
1171 data_readlines();
1172 buffer_init();
1173 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001174
Rob Landley9200e792005-09-15 19:26:59 +00001175 while (1) {
1176 keypress = tless_getch();
1177 keypress_process(keypress);
1178 }
1179}