blob: 1b993ea2c226a5ca4c7912b821694861211b4d0e [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 *
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +000023 * This program needs a lot of development, so consider it in a beta stage
24 * at best.
Rob Landley9200e792005-09-15 19:26:59 +000025 *
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +000026 * TODO:
27 * - 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
Rob Landley9200e792005-09-15 19:26:59 +000036 *
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +000037 * 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
Rob Landley9200e792005-09-15 19:26:59 +000043*/
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 */
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +000080#define CLEAR "\033[H\033[J"
Rob Landley9200e792005-09-15 19:26:59 +000081
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) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000145 tcsetattr(0, TCSANOW, &term_vi);
Rob Landley9200e792005-09-15 19:26:59 +0000146}
147
148/* Exit the program gracefully */
149static void tless_exit(int code) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000150
Rob Landley9200e792005-09-15 19:26:59 +0000151 /* TODO: We really should save the terminal state when we start,
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000152 and restore it when we exit. Less does this with the
Rob Landley9200e792005-09-15 19:26:59 +0000153 "ti" and "te" termcap commands; can this be done with
154 only termios.h? */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000155
Rob Landley9200e792005-09-15 19:26:59 +0000156 putchar('\n');
157 exit(code);
158}
159
160/* Grab a character from input without requiring the return key. If the
161 character is ASCII \033, get more characters and assign certain sequences
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000162 special return codes. Note that this function works best with raw input. */
163static int tless_getch(void) {
164
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000165 int input;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000166
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000167 set_tty_raw();
168
169 input = getc(inp);
Rob Landley9200e792005-09-15 19:26:59 +0000170 /* Detect escape sequences (i.e. arrow keys) and handle
171 them accordingly */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000172
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000173 if (input == '\033' && getc(inp) == '[') {
174 input = getc(inp);
Rob Landley9200e792005-09-15 19:26:59 +0000175 set_tty_cooked();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000176 if (input == REAL_KEY_UP)
177 return KEY_UP;
178 else if (input == REAL_KEY_DOWN)
179 return KEY_DOWN;
180 else if (input == REAL_KEY_RIGHT)
181 return KEY_RIGHT;
182 else if (input == REAL_KEY_LEFT)
183 return KEY_LEFT;
184 else if (input == REAL_PAGE_UP)
185 return PAGE_UP;
186 else if (input == REAL_PAGE_DOWN)
187 return PAGE_DOWN;
Rob Landley9200e792005-09-15 19:26:59 +0000188 }
189 /* The input is a normal ASCII value */
190 else {
191 set_tty_cooked();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000192 return input;
Rob Landley9200e792005-09-15 19:26:59 +0000193 }
194 return 0;
195}
196
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000197/* Move the cursor to a position (x,y), where (0,0) is the
Rob Landley9200e792005-09-15 19:26:59 +0000198 top-left corner of the console */
199static void move_cursor(int x, int y) {
200 printf("\033[%i;%iH", x, y);
201}
202
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000203static void clear_line(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000204 move_cursor(height, 0);
205 printf("\033[K");
206}
207
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000208/* This adds line numbers to every line, as the -N flag necessitates */
209static void add_linenumbers(void) {
210
211 char current_line[256];
212 int i;
213
214 for (i = 0; i <= num_flines; i++) {
215 safe_strncpy(current_line, flines[i], 256);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000216 bb_xasprintf(&flines[i],"%5d %s", i + 1, current_line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000217 }
218}
219
220static void data_readlines(void) {
221
Rob Landley9200e792005-09-15 19:26:59 +0000222 int i;
223 char current_line[256];
224 FILE *fp;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000225
Rob Landley9200e792005-09-15 19:26:59 +0000226 fp = (inp_stdin) ? stdin : bb_xfopen(filename, "rt");
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000227
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000228 /* First of all, we need to know the number of lines so that flines can be initialised. */
229 for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++)
230 fgets(current_line, 256, fp);
231 rewind(fp);
232 /* Initialise fp */
233 flines = malloc(i * sizeof(char *));
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000234
Rob Landley9200e792005-09-15 19:26:59 +0000235 for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++) {
236 strcpy(current_line, "");
237 fgets(current_line, 256, fp);
238 bb_xferror(fp, filename);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000239 flines[i] = bb_xstrdup(current_line);
Rob Landley9200e792005-09-15 19:26:59 +0000240 }
241 num_flines = i - 2;
242
243/* Reset variables for a new file */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000244
Rob Landley9200e792005-09-15 19:26:59 +0000245 line_pos = 0;
246 past_eof = 0;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000247
Rob Landley9200e792005-09-15 19:26:59 +0000248 fclose(fp);
249
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000250 inp = (inp_stdin) ? fopen(CURRENT_TTY, "r") : stdin;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000251
Rob Landley9200e792005-09-15 19:26:59 +0000252 if (ea_inp_stdin) {
253 fclose(inp);
254 inp = fopen(CURRENT_TTY, "r");
255 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000256
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000257 if (flags & FLAG_N)
Rob Landley9200e792005-09-15 19:26:59 +0000258 add_linenumbers();
259}
260
Rob Landley9200e792005-09-15 19:26:59 +0000261/* Turn a percentage into a line number */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000262static int reverse_percent(int percentage) {
Rob Landley9200e792005-09-15 19:26:59 +0000263 double linenum = percentage;
264 linenum = ((linenum / 100) * num_flines) - 1;
265 return(linenum);
266}
267
268#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000269
270/* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes
271 * on my build. */
272static int calc_percent(void) {
273 return ((100 * (line_pos + height - 2) / num_flines) + 1);
274}
275
Rob Landley9200e792005-09-15 19:26:59 +0000276/* Print a status line if -M was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000277static void m_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000278
279 int percentage;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000280
Rob Landley9200e792005-09-15 19:26:59 +0000281 if (!past_eof) {
282 if (!line_pos) {
283 if (num_files > 1)
284 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);
285 else {
286 printf("%s%s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
287 }
288 }
289 else {
290 printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
291 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000292
Rob Landley9200e792005-09-15 19:26:59 +0000293 if (line_pos == num_flines - height + 2) {
294 printf("(END) %s", NORMAL);
295 if ((num_files > 1) && (current_file != num_files))
296 printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL);
297 }
298 else {
299 percentage = calc_percent();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000300 printf("%i%% %s", percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000301 }
302 }
303 else {
304 printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, line_pos + 1, num_flines + 1, num_flines + 1);
305 if ((num_files > 1) && (current_file != num_files))
306 printf("- Next: %s", files[current_file]);
307 printf("%s", NORMAL);
308 }
309}
310
311/* Print a status line if -m was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000312static void medium_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000313
314 int percentage;
315 percentage = calc_percent();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000316
Rob Landley9200e792005-09-15 19:26:59 +0000317 if (!line_pos)
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000318 printf("%s%s %i%%%s", HIGHLIGHT, filename, percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000319 else if (line_pos == num_flines - height + 2)
320 printf("%s(END)%s", HIGHLIGHT, NORMAL);
321 else
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000322 printf("%s%i%%%s", HIGHLIGHT, percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000323}
324#endif
325
326/* Print the status line */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000327static void status_print(void) {
328
Rob Landley9200e792005-09-15 19:26:59 +0000329 /* Change the status if flags have been set */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000330#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000331 if (flags & FLAG_M)
Rob Landley9200e792005-09-15 19:26:59 +0000332 m_status_print();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000333 else if (flags & FLAG_m)
Rob Landley9200e792005-09-15 19:26:59 +0000334 medium_status_print();
335 /* No flags set */
336 else {
337#endif
338 if (!line_pos) {
339 printf("%s%s %s", HIGHLIGHT, filename, NORMAL);
340 if (num_files > 1)
341 printf("%s%s%i%s%i%s%s", HIGHLIGHT, "(file ", current_file, " of ", num_files, ")", NORMAL);
342 }
343 else if (line_pos == num_flines - height + 2) {
344 printf("%s%s %s", HIGHLIGHT, "(END)", NORMAL);
345 if ((num_files > 1) && (current_file != num_files))
346 printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL);
347 }
348 else {
349 printf("%c", ':');
350 }
351#ifdef CONFIG_FEATURE_LESS_FLAGS
352 }
353#endif
354}
355
356/* Print the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000357static void buffer_print(void) {
358
Rob Landley9200e792005-09-15 19:26:59 +0000359 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000360
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000361 printf("%s", CLEAR);
Rob Landley9200e792005-09-15 19:26:59 +0000362 if (num_flines >= height - 2) {
Rob Landley9200e792005-09-15 19:26:59 +0000363 for (i = 0; i < height - 1; i++)
364 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000365 }
366 else {
Rob Landley9200e792005-09-15 19:26:59 +0000367 for (i = 1; i < (height - 1 - num_flines); i++)
368 putchar('\n');
369 for (i = 0; i < height - 1; i++)
370 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000371 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000372
373 status_print();
Rob Landley9200e792005-09-15 19:26:59 +0000374}
375
376/* Initialise the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000377static void buffer_init(void) {
378
Rob Landley9200e792005-09-15 19:26:59 +0000379 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000380
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000381 if(buffer == NULL) {
382 /* malloc the number of lines needed for the buffer */
383 buffer = xrealloc(buffer, height * sizeof(char *));
384 } else {
385 for (i = 0; i < (height - 1); i++)
386 free(buffer[i]);
387 }
388
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000389 /* Fill the buffer until the end of the file or the
Rob Landley9200e792005-09-15 19:26:59 +0000390 end of the buffer is reached */
391 for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000392 buffer[i] = (char *) bb_xstrdup(flines[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000393 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000394
Rob Landley9200e792005-09-15 19:26:59 +0000395 /* If the buffer still isn't full, fill it with blank lines */
396 for (; i < (height - 1); i++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000397 buffer[i] = bb_xstrdup("");
Rob Landley9200e792005-09-15 19:26:59 +0000398 }
399}
400
401/* Move the buffer up and down in the file in order to scroll */
402static void buffer_down(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000403
Rob Landley9200e792005-09-15 19:26:59 +0000404 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000405
Rob Landley9200e792005-09-15 19:26:59 +0000406 if (!past_eof) {
407 if (line_pos + (height - 3) + nlines < num_flines) {
408 line_pos += nlines;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000409 for (i = 0; i < (height - 1); i++) {
410 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000411 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000412 }
Rob Landley9200e792005-09-15 19:26:59 +0000413 }
414 else {
415 /* As the number of lines requested was too large, we just move
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000416 to the end of the file */
417 while (line_pos + (height - 3) + 1 < num_flines) {
Rob Landley9200e792005-09-15 19:26:59 +0000418 line_pos += 1;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000419 for (i = 0; i < (height - 1); i++) {
420 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000421 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000422 }
Rob Landley9200e792005-09-15 19:26:59 +0000423 }
424 }
425
426 /* We exit if the -E flag has been set */
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000427 if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines))
Rob Landley9200e792005-09-15 19:26:59 +0000428 tless_exit(0);
429 }
430}
431
432static void buffer_up(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000433
Rob Landley9200e792005-09-15 19:26:59 +0000434 int i;
435 int tilde_line;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000436
Rob Landley9200e792005-09-15 19:26:59 +0000437 if (!past_eof) {
438 if (line_pos - nlines >= 0) {
439 line_pos -= nlines;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000440 for (i = 0; i < (height - 1); i++) {
441 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000442 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000443 }
Rob Landley9200e792005-09-15 19:26:59 +0000444 }
445 else {
446 /* As the requested number of lines to move was too large, we
447 move one line up at a time until we can't. */
448 while (line_pos != 0) {
449 line_pos -= 1;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000450 for (i = 0; i < (height - 1); i++) {
451 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000452 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000453 }
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++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000472 free(buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000473 if (i < tilde_line - nlines + 1)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000474 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000475 else {
476 if (line_pos >= num_flines - height + 2)
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000477 buffer[i] = bb_xstrdup("~\n");
Rob Landley9200e792005-09-15 19:26:59 +0000478 }
479 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000480 }
Rob Landley9200e792005-09-15 19:26:59 +0000481 }
482}
483
484static void buffer_line(int linenum) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000485
Rob Landley9200e792005-09-15 19:26:59 +0000486 int i;
487
488 past_eof = 0;
489
490 if (linenum < 1 || linenum > num_flines) {
491 clear_line();
492 printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum, NORMAL);
493 }
494 else if (linenum < (num_flines - height - 2)) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000495 for (i = 0; i < (height - 1); i++) {
496 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000497 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000498 }
Rob Landley9200e792005-09-15 19:26:59 +0000499 line_pos = linenum;
500 }
501 else {
502 for (i = 0; i < (height - 1); i++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000503 free(buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000504 if (linenum + i < num_flines + 2)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000505 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000506 else
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000507 buffer[i] = (char *) bb_xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n");
Rob Landley9200e792005-09-15 19:26:59 +0000508 }
509 line_pos = linenum;
510 /* Set past_eof so buffer_down and buffer_up act differently */
511 past_eof = 1;
512 }
513}
514
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000515/* Reinitialise everything for a new file - free the memory and start over */
516static void reinitialise(void) {
517
518 int i;
519
520 for (i = 0; i <= num_flines; i++)
521 free(flines[i]);
522 free(flines);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000523
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000524 data_readlines();
525 buffer_init();
526 buffer_print();
527}
528
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000529static void examine_file(void) {
530
531 int newline_offset;
532
533 clear_line();
534 printf("Examine: ");
535 fgets(filename, 256, inp);
536
537 /* As fgets adds a newline to the end of an input string, we
538 need to remove it */
539 newline_offset = strlen(filename) - 1;
540 filename[newline_offset] = '\0';
541
542 files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
543 current_file = num_files + 1;
544 num_files++;
545
546 inp_stdin = 0;
547 ea_inp_stdin = 1;
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000548 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000549}
550
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000551/* This function changes the file currently being paged. direction can be one of the following:
552 * -1: go back one file
553 * 0: go to the first file
554 * 1: go forward one file
555*/
556static void change_file (int direction) {
557 if (current_file != ((direction > 0) ? num_files : 1)) {
558 current_file = direction ? current_file + direction : 1;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000559 strcpy(filename, files[current_file - 1]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000560 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000561 }
562 else {
563 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000564 printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000565 }
566}
567
568static void remove_current_file(void) {
569
570 int i;
571
572 if (current_file != 1) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000573 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000574 for (i = 3; i <= num_files; i++)
575 files[i - 2] = files[i - 1];
576 num_files--;
577 buffer_print();
578 }
579 else {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000580 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000581 for (i = 2; i <= num_files; i++)
582 files[i - 2] = files[i - 1];
583 num_files--;
584 current_file--;
585 buffer_print();
586 }
587}
588
589static void colon_process(void) {
590
591 int keypress;
592
593 /* Clear the current line and print a prompt */
594 clear_line();
595 printf(" :");
596
597 keypress = tless_getch();
598 switch (keypress) {
599 case 'd':
600 remove_current_file();
601 break;
602 case 'e':
603 examine_file();
604 break;
605#ifdef CONFIG_FEATURE_LESS_FLAGS
606 case 'f':
607 clear_line();
608 m_status_print();
609 break;
610#endif
611 case 'n':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000612 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000613 break;
614 case 'p':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000615 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000616 break;
617 case 'q':
618 tless_exit(0);
619 break;
620 case 'x':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000621 change_file(0);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000622 break;
623 default:
624 break;
625 }
626}
627
628#ifdef CONFIG_FEATURE_LESS_REGEXP
629/* The below two regular expression handler functions NEED development. */
630
631/* Get a regular expression from the user, and then go through the current
632 file line by line, running a processing regex function on each one. */
633
634static char *insert_highlights (char *line, int start, int end) {
635
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000636 char *new_line;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000637
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000638 bb_xasprintf(&new_line, "%.*s%s%.*s%s%s", start, line, HIGHLIGHT,
639 end - start, line + start, NORMAL, line + end);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000640 return new_line;
641}
642
643static char *process_regex_on_line(char *line, regex_t *pattern) {
644 /* This function takes the regex and applies it to the line.
645 Each part of the line that matches has the HIGHLIGHT
646 and NORMAL escape sequences placed around it by
647 insert_highlights, and then the line is returned. */
648
649 int match_status;
650 char *line2 = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 64);
651 char sub_line[256];
652 int prev_eo = 0;
"Vladimir N. Oleynik"8d3c40d2005-09-16 13:16:01 +0000653 regmatch_t match_structs;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000654
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000655 memset(sub_line, 0, 256);
656 strcpy(line2, line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000657
658 match_found = 0;
659 match_status = regexec(pattern, line2, 1, &match_structs, 0);
660
661 while (match_status == 0) {
662
663 memset(sub_line, 0, 256);
664
665 if (match_found == 0)
666 match_found = 1;
667
668 line2 = insert_highlights(line2, match_structs.rm_so + prev_eo, match_structs.rm_eo + prev_eo);
669 if (match_structs.rm_eo + 11 + prev_eo < strlen(line2))
670 strcat(sub_line, line2 + match_structs.rm_eo + 11 + prev_eo);
671
672 prev_eo += match_structs.rm_eo + 11;
673 match_status = regexec(pattern, sub_line, 1, &match_structs, REG_NOTBOL);
674 }
675
676 return line2;
677}
678
679static void regex_process(void) {
680
681 char uncomp_regex[100];
682 char current_line[256];
683 int i;
684 int j = 0;
685 regex_t *pattern;
686
687 /* Reset variables */
688 match_lines[0] = -1;
689 match_pos = 0;
690 num_matches = 0;
691 match_found = 0;
692
693 pattern = (regex_t *) malloc(sizeof(regex_t));
694 memset(pattern, 0, sizeof(regex_t));
695
696 /* Get the uncompiled regular expression from the user */
697 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000698 putchar((match_backwards) ? '?' : '/');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000699 scanf("%s", uncomp_regex);
700
701 /* Compile the regex and check for errors */
702 xregcomp(pattern, uncomp_regex, 0);
703
704 /* Run the regex on each line of the current file here */
705 for (i = 0; i <= num_flines; i++) {
706 strcpy(current_line, process_regex_on_line(flines[i], pattern));
707 flines[i] = (char *) bb_xstrndup(current_line, sizeof(char) * (strlen(current_line)+1));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000708 if (match_found) {
709 match_lines[j] = i;
710 j++;
711 }
712 }
713
714 num_matches = j;
715
716 if ((match_lines[0] != -1) && (num_flines > height - 2))
717 buffer_line(match_lines[0]);
718 else
719 buffer_init();
720}
721
722static void goto_match(int match) {
723
724 /* This goes to a specific match - all line positions of matches are
725 stored within the match_lines[] array. */
726 if ((match < num_matches) && (match >= 0)) {
727 buffer_line(match_lines[match]);
728 match_pos = match;
729 }
730}
731
732static void search_backwards(void) {
733
734 int current_linepos = line_pos;
735 int i;
736
737 match_backwards = 1;
738 regex_process();
739
740 for (i = 0; i < num_matches; i++) {
741 if (match_lines[i] > current_linepos) {
742 buffer_line(match_lines[i - num_back_match]);
743 break;
744 }
745 }
746
747 /* Reset variables */
748 match_backwards = 0;
749 num_back_match = 1;
750
751}
752#endif
753
754static void number_process(int first_digit) {
755
756 int i = 1;
757 int num;
758 char num_input[80];
759 char keypress;
760 num_input[0] = first_digit;
761
762 /* Clear the current line, print a prompt, and then print the digit */
763 clear_line();
764 printf(":%c", first_digit);
765
766 /* Receive input until a letter is given */
767 while((num_input[i] = tless_getch()) && isdigit(num_input[i])) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000768 printf("%c", num_input[i]);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000769 i++;
770 }
771
772 /* Take the final letter out of the digits string */
773 keypress = num_input[i];
774 num_input[i] = '\0';
775 i--;
776 num = atoi(num_input);
777
778 /* We now know the number and the letter entered, so we process them */
779 switch (keypress) {
780 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
781 buffer_down(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000782 break;
783 case KEY_UP: case 'b': case 'w': case 'y': case 'u':
784 buffer_up(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000785 break;
786 case 'g': case '<': case 'G': case '>':
787 if (num_flines >= height - 2)
788 buffer_line(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000789 break;
790 case 'p': case '%':
791 buffer_line(reverse_percent(num));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000792 break;
793#ifdef CONFIG_FEATURE_LESS_REGEXP
794 case 'n':
795 goto_match(match_pos + num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000796 break;
797 case '/':
798 regex_process();
799 goto_match(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000800 break;
801 case '?':
802 num_back_match = num;
803 search_backwards();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000804 break;
805#endif
806 default:
807 break;
808 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000809
810 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000811}
812
813#ifdef CONFIG_FEATURE_LESS_FLAGCS
814static void flag_change(void) {
815
816 int keypress;
817
818 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000819 putchar('-');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000820 keypress = tless_getch();
821
822 switch (keypress) {
823 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000824 flags &= ~FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000825 break;
826 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000827 flags &= ~FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000828 break;
829 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000830 flags &= ~FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000831 break;
832 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000833 flags &= ~FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000834 break;
835 default:
836 break;
837 }
838}
839
840static void show_flag_status(void) {
841
842 int keypress;
843 int flag_val;
844
845 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000846 putchar('_');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000847 keypress = tless_getch();
848
849 switch (keypress) {
850 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000851 flag_val = flags & FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000852 break;
853 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000854 flag_val = flags & FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000855 break;
856 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000857 flag_val = flags & FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000858 break;
859 case 'N':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000860 flag_val = flags & FLAG_N;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000861 break;
862 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000863 flag_val = flags & FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000864 break;
865 default:
866 flag_val = 0;
867 break;
868 }
869
870 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000871 printf("%s%s%i%s", HIGHLIGHT, "The status of the flag is: ", flag_val != 0, NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000872}
873#endif
874
875static void full_repaint(void) {
876
877 int temp_line_pos = line_pos;
878 data_readlines();
879 buffer_init();
880 buffer_line(temp_line_pos);
881 buffer_print();
882}
883
884
885static void save_input_to_file(void) {
886
887 char current_line[256];
888 int i;
889 FILE *fp;
890
891 clear_line();
892 printf("Log file: ");
893 fgets(current_line, 256, inp);
894 current_line[strlen(current_line) - 1] = '\0';
895 if (strlen(current_line)) {
896 fp = bb_xfopen(current_line, "w");
897 for (i = 0; i < num_flines; i++)
898 fprintf(fp, "%s", flines[i]);
899 fclose(fp);
900 buffer_print();
901 }
902 else
903 printf("%sNo log file%s", HIGHLIGHT, NORMAL);
904}
905
906#ifdef CONFIG_FEATURE_LESS_MARKS
907static void add_mark(void) {
908
909 int letter;
910 int mark_line;
911
912 clear_line();
913 printf("Mark: ");
914 letter = tless_getch();
915
916 if (isalpha(letter)) {
917 mark_line = line_pos;
918
919 /* If we exceed 15 marks, start overwriting previous ones */
920 if (num_marks == 14)
921 num_marks = 0;
922
923 mark_lines[num_marks][0] = letter;
924 mark_lines[num_marks][1] = line_pos;
925 num_marks++;
926 }
927 else {
928 clear_line();
929 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
930 }
931}
932
933static void goto_mark(void) {
934
935 int letter;
936 int i;
937
938 clear_line();
939 printf("Go to mark: ");
940 letter = tless_getch();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000941 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000942
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000943 if (isalpha(letter)) {
944 for (i = 0; i <= num_marks; i++)
945 if (letter == mark_lines[i][0]) {
946 buffer_line(mark_lines[i][1]);
947 break;
948 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000949 if ((num_marks == 14) && (letter != mark_lines[14][0]))
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000950 printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000951 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000952 else
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000953 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000954}
955#endif
956
957
958#ifdef CONFIG_FEATURE_LESS_BRACKETS
959
960static char opp_bracket (char bracket) {
961
962 switch (bracket) {
963 case '{': case '[':
964 return bracket + 2;
965 break;
966 case '(':
967 return ')';
968 break;
969 case '}': case ']':
970 return bracket - 2;
971 break;
972 case ')':
973 return '(';
974 break;
975 default:
976 return 0;
977 break;
978 }
979}
980
981static void match_right_bracket(char bracket) {
982
983 int bracket_line = -1;
984 int i;
985
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000986 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000987
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000988 if (strchr(flines[line_pos], bracket) == NULL)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000989 printf("%s%s%s", HIGHLIGHT, "No bracket in top line", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000990 else {
991 for (i = line_pos + 1; i < num_flines; i++) {
992 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
993 bracket_line = i;
994 break;
995 }
996 }
997
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000998 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000999 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001000
1001 buffer_line(bracket_line - height + 2);
1002 buffer_print();
1003 }
1004}
1005
1006static void match_left_bracket (char bracket) {
1007
1008 int bracket_line = -1;
1009 int i;
1010
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001011 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +00001012
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001013 if (strchr(flines[line_pos + height - 2], bracket) == NULL) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001014 printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL);
1015 printf("%s", flines[line_pos + height]);
1016 sleep(4);
1017 }
1018 else {
1019 for (i = line_pos + height - 2; i >= 0; i--) {
1020 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
1021 bracket_line = i;
1022 break;
1023 }
1024 }
1025
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001026 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001027 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001028
1029 buffer_line(bracket_line);
1030 buffer_print();
1031 }
1032}
1033
1034#endif /* CONFIG_FEATURE_LESS_BRACKETS */
1035
Rob Landley9200e792005-09-15 19:26:59 +00001036static void keypress_process(int keypress) {
1037 switch (keypress) {
1038 case KEY_DOWN: case 'e': case 'j': case '\015':
1039 buffer_down(1);
1040 buffer_print();
1041 break;
1042 case KEY_UP: case 'y': case 'k':
1043 buffer_up(1);
1044 buffer_print();
1045 break;
1046 case PAGE_DOWN: case ' ': case 'z':
1047 buffer_down(height - 1);
1048 buffer_print();
1049 break;
1050 case PAGE_UP: case 'w': case 'b':
1051 buffer_up(height - 1);
1052 buffer_print();
1053 break;
1054 case 'd':
1055 buffer_down((height - 1) / 2);
1056 buffer_print();
1057 break;
1058 case 'u':
1059 buffer_up((height - 1) / 2);
1060 buffer_print();
1061 break;
1062 case 'g': case 'p': case '<': case '%':
1063 buffer_up(num_flines + 1);
1064 buffer_print();
1065 break;
1066 case 'G': case '>':
1067 buffer_down(num_flines + 1);
1068 buffer_print();
1069 break;
1070 case 'q': case 'Q':
1071 tless_exit(0);
1072 break;
1073#ifdef CONFIG_FEATURE_LESS_MARKS
1074 case 'm':
1075 add_mark();
1076 buffer_print();
1077 break;
1078 case '\'':
1079 goto_mark();
1080 buffer_print();
1081 break;
1082#endif
1083 case 'r':
1084 buffer_print();
1085 break;
1086 case 'R':
1087 full_repaint();
1088 break;
1089 case 's':
1090 if (inp_stdin)
1091 save_input_to_file();
1092 break;
1093 case 'E':
1094 examine_file();
1095 break;
1096#ifdef CONFIG_FEATURE_LESS_FLAGS
1097 case '=':
1098 clear_line();
1099 m_status_print();
1100 break;
1101#endif
1102#ifdef CONFIG_FEATURE_LESS_REGEXP
1103 case '/':
1104 regex_process();
1105 buffer_print();
1106 break;
1107 case 'n':
1108 goto_match(match_pos + 1);
1109 buffer_print();
1110 break;
1111 case 'N':
1112 goto_match(match_pos - 1);
1113 buffer_print();
1114 break;
1115 case '?':
1116 search_backwards();
1117 buffer_print();
1118 break;
1119#endif
1120#ifdef CONFIG_FEATURE_LESS_FLAGCS
1121 case '-':
1122 flag_change();
1123 buffer_print();
1124 break;
1125 case '_':
1126 show_flag_status();
1127 break;
1128#endif
1129#ifdef CONFIG_FEATURE_LESS_BRACKETS
1130 case '{': case '(': case '[':
1131 match_right_bracket(keypress);
1132 break;
1133 case '}': case ')': case ']':
1134 match_left_bracket(keypress);
1135 break;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001136#endif
1137 case ':':
Rob Landley9200e792005-09-15 19:26:59 +00001138 colon_process();
1139 break;
1140 default:
1141 break;
1142 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001143
Rob Landley9200e792005-09-15 19:26:59 +00001144 if (isdigit(keypress))
1145 number_process(keypress);
1146}
1147
Rob Landley9200e792005-09-15 19:26:59 +00001148int less_main(int argc, char **argv) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001149
Rob Landley9200e792005-09-15 19:26:59 +00001150 int keypress;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001151
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001152 flags = bb_getopt_ulflags(argc, argv, "EMmN~");
Rob Landley9200e792005-09-15 19:26:59 +00001153
1154 argc -= optind;
1155 argv += optind;
1156 files = argv;
1157 num_files = argc;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001158
Rob Landley9200e792005-09-15 19:26:59 +00001159 if (!num_files) {
1160 if (ttyname(STDIN_FILENO) == NULL)
1161 inp_stdin = 1;
1162 else {
1163 bb_error_msg("Missing filename");
1164 bb_show_usage();
1165 }
1166 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001167
Rob Landley9200e792005-09-15 19:26:59 +00001168 strcpy(filename, (inp_stdin) ? "stdin" : files[0]);
1169 tty_width_height();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +00001170 tcgetattr(0, &term_orig);
1171 term_vi = term_orig;
1172 term_vi.c_lflag &= (~ICANON & ~ECHO);
1173 term_vi.c_iflag &= (~IXON & ~ICRNL);
1174 term_vi.c_oflag &= (~ONLCR);
1175 term_vi.c_cc[VMIN] = 1;
1176 term_vi.c_cc[VTIME] = 0;
1177
Rob Landley9200e792005-09-15 19:26:59 +00001178 data_readlines();
1179 buffer_init();
1180 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001181
Rob Landley9200e792005-09-15 19:26:59 +00001182 while (1) {
1183 keypress = tless_getch();
1184 keypress_process(keypress);
1185 }
1186}