blob: 5bf59a13045d765bbe33879ab453fdd0ec943c59 [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
112#ifdef CONFIG_FEATURE_LESS_MARKS
113static int mark_lines[15][2];
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000114static int num_marks;
Rob Landley9200e792005-09-15 19:26:59 +0000115#endif
116
117#ifdef CONFIG_FEATURE_LESS_REGEXP
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000118static int match_found;
Rob Landley9200e792005-09-15 19:26:59 +0000119static int match_lines[100];
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000120static int match_pos;
121static int num_matches;
122static int match_backwards;
Rob Landley9200e792005-09-15 19:26:59 +0000123static int num_back_match = 1;
124#endif
125
126/* Needed termios structures */
127static struct termios term_orig, term_vi;
128
129/* File pointer to get input from */
130static FILE *inp;
131
132/* Reset terminal input to normal */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000133static void set_tty_cooked(void) {
134 fflush(stdout);
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000135 tcsetattr(fileno(inp), TCSANOW, &term_orig);
Rob Landley9200e792005-09-15 19:26:59 +0000136}
137
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000138/* Set terminal input to raw mode (taken from vi.c) */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000139static void set_tty_raw(void) {
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000140 tcsetattr(fileno(inp), TCSANOW, &term_vi);
Rob Landley9200e792005-09-15 19:26:59 +0000141}
142
143/* Exit the program gracefully */
144static void tless_exit(int code) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000145
Rob Landley9200e792005-09-15 19:26:59 +0000146 /* TODO: We really should save the terminal state when we start,
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000147 and restore it when we exit. Less does this with the
Rob Landley9200e792005-09-15 19:26:59 +0000148 "ti" and "te" termcap commands; can this be done with
149 only termios.h? */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000150
Rob Landley9200e792005-09-15 19:26:59 +0000151 putchar('\n');
152 exit(code);
153}
154
155/* Grab a character from input without requiring the return key. If the
156 character is ASCII \033, get more characters and assign certain sequences
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000157 special return codes. Note that this function works best with raw input. */
158static int tless_getch(void) {
159
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000160 int input;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000161
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000162 set_tty_raw();
163
164 input = getc(inp);
Rob Landley9200e792005-09-15 19:26:59 +0000165 /* Detect escape sequences (i.e. arrow keys) and handle
166 them accordingly */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000167
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000168 if (input == '\033' && getc(inp) == '[') {
169 input = getc(inp);
Rob Landley9200e792005-09-15 19:26:59 +0000170 set_tty_cooked();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000171 if (input == REAL_KEY_UP)
172 return KEY_UP;
173 else if (input == REAL_KEY_DOWN)
174 return KEY_DOWN;
175 else if (input == REAL_KEY_RIGHT)
176 return KEY_RIGHT;
177 else if (input == REAL_KEY_LEFT)
178 return KEY_LEFT;
179 else if (input == REAL_PAGE_UP)
180 return PAGE_UP;
181 else if (input == REAL_PAGE_DOWN)
182 return PAGE_DOWN;
Rob Landley9200e792005-09-15 19:26:59 +0000183 }
184 /* The input is a normal ASCII value */
185 else {
186 set_tty_cooked();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000187 return input;
Rob Landley9200e792005-09-15 19:26:59 +0000188 }
189 return 0;
190}
191
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000192/* Move the cursor to a position (x,y), where (0,0) is the
Rob Landley9200e792005-09-15 19:26:59 +0000193 top-left corner of the console */
194static void move_cursor(int x, int y) {
195 printf("\033[%i;%iH", x, y);
196}
197
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000198static void clear_line(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000199 move_cursor(height, 0);
200 printf("\033[K");
201}
202
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000203/* This adds line numbers to every line, as the -N flag necessitates */
204static void add_linenumbers(void) {
205
206 char current_line[256];
207 int i;
208
209 for (i = 0; i <= num_flines; i++) {
210 safe_strncpy(current_line, flines[i], 256);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000211 bb_xasprintf(&flines[i],"%5d %s", i + 1, current_line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000212 }
213}
214
215static void data_readlines(void) {
216
Rob Landley9200e792005-09-15 19:26:59 +0000217 int i;
218 char current_line[256];
219 FILE *fp;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000220
Rob Landley9200e792005-09-15 19:26:59 +0000221 fp = (inp_stdin) ? stdin : bb_xfopen(filename, "rt");
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000222 flines = NULL;
223 for (i = 0; (feof(fp)==0) && (i <= MAXLINES); i++) {
Rob Landley9200e792005-09-15 19:26:59 +0000224 strcpy(current_line, "");
225 fgets(current_line, 256, fp);
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000226 if(fp != stdin)
227 bb_xferror(fp, filename);
228 flines = xrealloc(flines, (i+1) * sizeof(char *));
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000229 flines[i] = bb_xstrdup(current_line);
Rob Landley9200e792005-09-15 19:26:59 +0000230 }
231 num_flines = i - 2;
232
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000233 /* Reset variables for a new file */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000234
Rob Landley9200e792005-09-15 19:26:59 +0000235 line_pos = 0;
236 past_eof = 0;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000237
Rob Landley9200e792005-09-15 19:26:59 +0000238 fclose(fp);
239
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000240 if(inp == NULL)
241 inp = (inp_stdin) ? fopen(CURRENT_TTY, "r") : stdin;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000242
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000243 if (flags & FLAG_N)
Rob Landley9200e792005-09-15 19:26:59 +0000244 add_linenumbers();
245}
246
Rob Landley9200e792005-09-15 19:26:59 +0000247/* Turn a percentage into a line number */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000248static int reverse_percent(int percentage) {
Rob Landley9200e792005-09-15 19:26:59 +0000249 double linenum = percentage;
250 linenum = ((linenum / 100) * num_flines) - 1;
251 return(linenum);
252}
253
254#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000255
256/* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes
257 * on my build. */
258static int calc_percent(void) {
259 return ((100 * (line_pos + height - 2) / num_flines) + 1);
260}
261
Rob Landley9200e792005-09-15 19:26:59 +0000262/* Print a status line if -M was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000263static void m_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000264
265 int percentage;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000266
Rob Landley9200e792005-09-15 19:26:59 +0000267 if (!past_eof) {
268 if (!line_pos) {
269 if (num_files > 1)
270 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);
271 else {
272 printf("%s%s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
273 }
274 }
275 else {
276 printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
277 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000278
Rob Landley9200e792005-09-15 19:26:59 +0000279 if (line_pos == num_flines - height + 2) {
280 printf("(END) %s", NORMAL);
281 if ((num_files > 1) && (current_file != num_files))
282 printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL);
283 }
284 else {
285 percentage = calc_percent();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000286 printf("%i%% %s", percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000287 }
288 }
289 else {
290 printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, line_pos + 1, num_flines + 1, num_flines + 1);
291 if ((num_files > 1) && (current_file != num_files))
292 printf("- Next: %s", files[current_file]);
293 printf("%s", NORMAL);
294 }
295}
296
297/* Print a status line if -m was specified */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000298static void medium_status_print(void) {
Rob Landley9200e792005-09-15 19:26:59 +0000299
300 int percentage;
301 percentage = calc_percent();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000302
Rob Landley9200e792005-09-15 19:26:59 +0000303 if (!line_pos)
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000304 printf("%s%s %i%%%s", HIGHLIGHT, filename, percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000305 else if (line_pos == num_flines - height + 2)
306 printf("%s(END)%s", HIGHLIGHT, NORMAL);
307 else
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000308 printf("%s%i%%%s", HIGHLIGHT, percentage, NORMAL);
Rob Landley9200e792005-09-15 19:26:59 +0000309}
310#endif
311
312/* Print the status line */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000313static void status_print(void) {
314
Rob Landley9200e792005-09-15 19:26:59 +0000315 /* Change the status if flags have been set */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000316#ifdef CONFIG_FEATURE_LESS_FLAGS
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000317 if (flags & FLAG_M)
Rob Landley9200e792005-09-15 19:26:59 +0000318 m_status_print();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000319 else if (flags & FLAG_m)
Rob Landley9200e792005-09-15 19:26:59 +0000320 medium_status_print();
321 /* No flags set */
322 else {
323#endif
324 if (!line_pos) {
325 printf("%s%s %s", HIGHLIGHT, filename, NORMAL);
326 if (num_files > 1)
327 printf("%s%s%i%s%i%s%s", HIGHLIGHT, "(file ", current_file, " of ", num_files, ")", NORMAL);
328 }
329 else if (line_pos == num_flines - height + 2) {
330 printf("%s%s %s", HIGHLIGHT, "(END)", NORMAL);
331 if ((num_files > 1) && (current_file != num_files))
332 printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL);
333 }
334 else {
335 printf("%c", ':');
336 }
337#ifdef CONFIG_FEATURE_LESS_FLAGS
338 }
339#endif
340}
341
342/* Print the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000343static void buffer_print(void) {
344
Rob Landley9200e792005-09-15 19:26:59 +0000345 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000346
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000347 printf("%s", CLEAR);
Rob Landley9200e792005-09-15 19:26:59 +0000348 if (num_flines >= height - 2) {
Rob Landley9200e792005-09-15 19:26:59 +0000349 for (i = 0; i < height - 1; i++)
350 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000351 }
352 else {
Rob Landley9200e792005-09-15 19:26:59 +0000353 for (i = 1; i < (height - 1 - num_flines); i++)
354 putchar('\n');
355 for (i = 0; i < height - 1; i++)
356 printf("%s", buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000357 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000358
359 status_print();
Rob Landley9200e792005-09-15 19:26:59 +0000360}
361
362/* Initialise the buffer */
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000363static void buffer_init(void) {
364
Rob Landley9200e792005-09-15 19:26:59 +0000365 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000366
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000367 if(buffer == NULL) {
368 /* malloc the number of lines needed for the buffer */
369 buffer = xrealloc(buffer, height * sizeof(char *));
370 } else {
371 for (i = 0; i < (height - 1); i++)
372 free(buffer[i]);
373 }
374
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000375 /* Fill the buffer until the end of the file or the
Rob Landley9200e792005-09-15 19:26:59 +0000376 end of the buffer is reached */
377 for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000378 buffer[i] = (char *) bb_xstrdup(flines[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000379 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000380
Rob Landley9200e792005-09-15 19:26:59 +0000381 /* If the buffer still isn't full, fill it with blank lines */
382 for (; i < (height - 1); i++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000383 buffer[i] = bb_xstrdup("");
Rob Landley9200e792005-09-15 19:26:59 +0000384 }
385}
386
387/* Move the buffer up and down in the file in order to scroll */
388static void buffer_down(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000389
Rob Landley9200e792005-09-15 19:26:59 +0000390 int i;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000391
Rob Landley9200e792005-09-15 19:26:59 +0000392 if (!past_eof) {
393 if (line_pos + (height - 3) + nlines < num_flines) {
394 line_pos += nlines;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000395 for (i = 0; i < (height - 1); i++) {
396 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000397 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000398 }
Rob Landley9200e792005-09-15 19:26:59 +0000399 }
400 else {
401 /* As the number of lines requested was too large, we just move
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000402 to the end of the file */
403 while (line_pos + (height - 3) + 1 < num_flines) {
Rob Landley9200e792005-09-15 19:26:59 +0000404 line_pos += 1;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000405 for (i = 0; i < (height - 1); i++) {
406 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000407 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000408 }
Rob Landley9200e792005-09-15 19:26:59 +0000409 }
410 }
411
412 /* We exit if the -E flag has been set */
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000413 if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines))
Rob Landley9200e792005-09-15 19:26:59 +0000414 tless_exit(0);
415 }
416}
417
418static void buffer_up(int nlines) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000419
Rob Landley9200e792005-09-15 19:26:59 +0000420 int i;
421 int tilde_line;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000422
Rob Landley9200e792005-09-15 19:26:59 +0000423 if (!past_eof) {
424 if (line_pos - nlines >= 0) {
425 line_pos -= nlines;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000426 for (i = 0; i < (height - 1); i++) {
427 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000428 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000429 }
Rob Landley9200e792005-09-15 19:26:59 +0000430 }
431 else {
432 /* As the requested number of lines to move was too large, we
433 move one line up at a time until we can't. */
434 while (line_pos != 0) {
435 line_pos -= 1;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000436 for (i = 0; i < (height - 1); i++) {
437 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000438 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000439 }
Rob Landley9200e792005-09-15 19:26:59 +0000440 }
441 }
442 }
443 else {
444 /* Work out where the tildes start */
445 tilde_line = num_flines - line_pos + 3;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000446
Rob Landley9200e792005-09-15 19:26:59 +0000447 line_pos -= nlines;
448 /* Going backwards nlines lines has taken us to a point where
449 nothing is past the EOF, so we revert to normal. */
450 if (line_pos < num_flines - height + 3) {
451 past_eof = 0;
452 buffer_up(nlines);
453 }
454 else {
455 /* We only move part of the buffer, as the rest
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000456 is past the EOF */
Rob Landley9200e792005-09-15 19:26:59 +0000457 for (i = 0; i < (height - 1); i++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000458 free(buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000459 if (i < tilde_line - nlines + 1)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000460 buffer[i] = (char *) bb_xstrdup(flines[line_pos + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000461 else {
462 if (line_pos >= num_flines - height + 2)
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000463 buffer[i] = bb_xstrdup("~\n");
Rob Landley9200e792005-09-15 19:26:59 +0000464 }
465 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000466 }
Rob Landley9200e792005-09-15 19:26:59 +0000467 }
468}
469
470static void buffer_line(int linenum) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000471
Rob Landley9200e792005-09-15 19:26:59 +0000472 int i;
473
474 past_eof = 0;
475
476 if (linenum < 1 || linenum > num_flines) {
477 clear_line();
478 printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum, NORMAL);
479 }
480 else if (linenum < (num_flines - height - 2)) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000481 for (i = 0; i < (height - 1); i++) {
482 free(buffer[i]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000483 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000484 }
Rob Landley9200e792005-09-15 19:26:59 +0000485 line_pos = linenum;
486 }
487 else {
488 for (i = 0; i < (height - 1); i++) {
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000489 free(buffer[i]);
Rob Landley9200e792005-09-15 19:26:59 +0000490 if (linenum + i < num_flines + 2)
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000491 buffer[i] = (char *) bb_xstrdup(flines[linenum + i]);
Rob Landley9200e792005-09-15 19:26:59 +0000492 else
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000493 buffer[i] = (char *) bb_xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n");
Rob Landley9200e792005-09-15 19:26:59 +0000494 }
495 line_pos = linenum;
496 /* Set past_eof so buffer_down and buffer_up act differently */
497 past_eof = 1;
498 }
499}
500
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000501/* Reinitialise everything for a new file - free the memory and start over */
502static void reinitialise(void) {
503
504 int i;
505
506 for (i = 0; i <= num_flines; i++)
507 free(flines[i]);
508 free(flines);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000509
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000510 data_readlines();
511 buffer_init();
512 buffer_print();
513}
514
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000515static void examine_file(void) {
516
517 int newline_offset;
518
519 clear_line();
520 printf("Examine: ");
521 fgets(filename, 256, inp);
522
523 /* As fgets adds a newline to the end of an input string, we
524 need to remove it */
525 newline_offset = strlen(filename) - 1;
526 filename[newline_offset] = '\0';
527
528 files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
529 current_file = num_files + 1;
530 num_files++;
531
532 inp_stdin = 0;
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000533 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000534}
535
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000536/* This function changes the file currently being paged. direction can be one of the following:
537 * -1: go back one file
538 * 0: go to the first file
539 * 1: go forward one file
540*/
541static void change_file (int direction) {
542 if (current_file != ((direction > 0) ? num_files : 1)) {
543 current_file = direction ? current_file + direction : 1;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000544 strcpy(filename, files[current_file - 1]);
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000545 reinitialise();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000546 }
547 else {
548 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000549 printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000550 }
551}
552
553static void remove_current_file(void) {
554
555 int i;
556
557 if (current_file != 1) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000558 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000559 for (i = 3; i <= num_files; i++)
560 files[i - 2] = files[i - 1];
561 num_files--;
562 buffer_print();
563 }
564 else {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000565 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000566 for (i = 2; i <= num_files; i++)
567 files[i - 2] = files[i - 1];
568 num_files--;
569 current_file--;
570 buffer_print();
571 }
572}
573
574static void colon_process(void) {
575
576 int keypress;
577
578 /* Clear the current line and print a prompt */
579 clear_line();
580 printf(" :");
581
582 keypress = tless_getch();
583 switch (keypress) {
584 case 'd':
585 remove_current_file();
586 break;
587 case 'e':
588 examine_file();
589 break;
590#ifdef CONFIG_FEATURE_LESS_FLAGS
591 case 'f':
592 clear_line();
593 m_status_print();
594 break;
595#endif
596 case 'n':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000597 change_file(1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000598 break;
599 case 'p':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000600 change_file(-1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000601 break;
602 case 'q':
603 tless_exit(0);
604 break;
605 case 'x':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000606 change_file(0);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000607 break;
608 default:
609 break;
610 }
611}
612
613#ifdef CONFIG_FEATURE_LESS_REGEXP
614/* The below two regular expression handler functions NEED development. */
615
616/* Get a regular expression from the user, and then go through the current
617 file line by line, running a processing regex function on each one. */
618
619static char *insert_highlights (char *line, int start, int end) {
620
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000621 char *new_line;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000622
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000623 bb_xasprintf(&new_line, "%.*s%s%.*s%s%s", start, line, HIGHLIGHT,
624 end - start, line + start, NORMAL, line + end);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000625 return new_line;
626}
627
628static char *process_regex_on_line(char *line, regex_t *pattern) {
629 /* This function takes the regex and applies it to the line.
630 Each part of the line that matches has the HIGHLIGHT
631 and NORMAL escape sequences placed around it by
632 insert_highlights, and then the line is returned. */
633
634 int match_status;
635 char *line2 = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 64);
636 char sub_line[256];
637 int prev_eo = 0;
"Vladimir N. Oleynik"8d3c40d2005-09-16 13:16:01 +0000638 regmatch_t match_structs;
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000639
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000640 memset(sub_line, 0, 256);
641 strcpy(line2, line);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000642
643 match_found = 0;
644 match_status = regexec(pattern, line2, 1, &match_structs, 0);
645
646 while (match_status == 0) {
647
648 memset(sub_line, 0, 256);
649
650 if (match_found == 0)
651 match_found = 1;
652
653 line2 = insert_highlights(line2, match_structs.rm_so + prev_eo, match_structs.rm_eo + prev_eo);
654 if (match_structs.rm_eo + 11 + prev_eo < strlen(line2))
655 strcat(sub_line, line2 + match_structs.rm_eo + 11 + prev_eo);
656
657 prev_eo += match_structs.rm_eo + 11;
658 match_status = regexec(pattern, sub_line, 1, &match_structs, REG_NOTBOL);
659 }
660
661 return line2;
662}
663
664static void regex_process(void) {
665
666 char uncomp_regex[100];
667 char current_line[256];
668 int i;
669 int j = 0;
670 regex_t *pattern;
671
672 /* Reset variables */
673 match_lines[0] = -1;
674 match_pos = 0;
675 num_matches = 0;
676 match_found = 0;
677
678 pattern = (regex_t *) malloc(sizeof(regex_t));
679 memset(pattern, 0, sizeof(regex_t));
680
681 /* Get the uncompiled regular expression from the user */
682 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000683 putchar((match_backwards) ? '?' : '/');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000684 scanf("%s", uncomp_regex);
685
686 /* Compile the regex and check for errors */
687 xregcomp(pattern, uncomp_regex, 0);
688
689 /* Run the regex on each line of the current file here */
690 for (i = 0; i <= num_flines; i++) {
691 strcpy(current_line, process_regex_on_line(flines[i], pattern));
692 flines[i] = (char *) bb_xstrndup(current_line, sizeof(char) * (strlen(current_line)+1));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000693 if (match_found) {
694 match_lines[j] = i;
695 j++;
696 }
697 }
698
699 num_matches = j;
700
701 if ((match_lines[0] != -1) && (num_flines > height - 2))
702 buffer_line(match_lines[0]);
703 else
704 buffer_init();
705}
706
707static void goto_match(int match) {
708
709 /* This goes to a specific match - all line positions of matches are
710 stored within the match_lines[] array. */
711 if ((match < num_matches) && (match >= 0)) {
712 buffer_line(match_lines[match]);
713 match_pos = match;
714 }
715}
716
717static void search_backwards(void) {
718
719 int current_linepos = line_pos;
720 int i;
721
722 match_backwards = 1;
723 regex_process();
724
725 for (i = 0; i < num_matches; i++) {
726 if (match_lines[i] > current_linepos) {
727 buffer_line(match_lines[i - num_back_match]);
728 break;
729 }
730 }
731
732 /* Reset variables */
733 match_backwards = 0;
734 num_back_match = 1;
735
736}
737#endif
738
739static void number_process(int first_digit) {
740
741 int i = 1;
742 int num;
743 char num_input[80];
744 char keypress;
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000745 char *endptr;
746
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000747 num_input[0] = first_digit;
748
749 /* Clear the current line, print a prompt, and then print the digit */
750 clear_line();
751 printf(":%c", first_digit);
752
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000753 /* Receive input until a letter is given (max 80 chars)*/
754 while((i < 80) && (num_input[i] = tless_getch()) && isdigit(num_input[i])) {
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000755 printf("%c", num_input[i]);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000756 i++;
757 }
758
759 /* Take the final letter out of the digits string */
760 keypress = num_input[i];
761 num_input[i] = '\0';
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000762 num = strtol(num_input, &endptr, 10);
763 if (endptr==num_input || *endptr!='\0' || num < 1 || num > MAXLINES)
764 goto END;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000765
766 /* We now know the number and the letter entered, so we process them */
767 switch (keypress) {
768 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
769 buffer_down(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000770 break;
771 case KEY_UP: case 'b': case 'w': case 'y': case 'u':
772 buffer_up(num);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000773 break;
774 case 'g': case '<': case 'G': case '>':
775 if (num_flines >= height - 2)
776 buffer_line(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000777 break;
778 case 'p': case '%':
779 buffer_line(reverse_percent(num));
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000780 break;
781#ifdef CONFIG_FEATURE_LESS_REGEXP
782 case 'n':
783 goto_match(match_pos + num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000784 break;
785 case '/':
786 regex_process();
787 goto_match(num - 1);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000788 break;
789 case '?':
790 num_back_match = num;
791 search_backwards();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000792 break;
793#endif
794 default:
795 break;
796 }
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +0000797END:
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000798 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000799}
800
801#ifdef CONFIG_FEATURE_LESS_FLAGCS
802static void flag_change(void) {
803
804 int keypress;
805
806 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000807 putchar('-');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000808 keypress = tless_getch();
809
810 switch (keypress) {
811 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000812 flags &= ~FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000813 break;
814 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000815 flags &= ~FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000816 break;
817 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000818 flags &= ~FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000819 break;
820 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000821 flags &= ~FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000822 break;
823 default:
824 break;
825 }
826}
827
828static void show_flag_status(void) {
829
830 int keypress;
831 int flag_val;
832
833 clear_line();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000834 putchar('_');
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000835 keypress = tless_getch();
836
837 switch (keypress) {
838 case 'M':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000839 flag_val = flags & FLAG_M;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000840 break;
841 case 'm':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000842 flag_val = flags & FLAG_m;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000843 break;
844 case '~':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000845 flag_val = flags & FLAG_TILDE;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000846 break;
847 case 'N':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000848 flag_val = flags & FLAG_N;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000849 break;
850 case 'E':
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000851 flag_val = flags & FLAG_E;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000852 break;
853 default:
854 flag_val = 0;
855 break;
856 }
857
858 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000859 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 +0000860}
861#endif
862
863static void full_repaint(void) {
864
865 int temp_line_pos = line_pos;
866 data_readlines();
867 buffer_init();
868 buffer_line(temp_line_pos);
869 buffer_print();
870}
871
872
873static void save_input_to_file(void) {
874
875 char current_line[256];
876 int i;
877 FILE *fp;
878
879 clear_line();
880 printf("Log file: ");
881 fgets(current_line, 256, inp);
882 current_line[strlen(current_line) - 1] = '\0';
883 if (strlen(current_line)) {
884 fp = bb_xfopen(current_line, "w");
885 for (i = 0; i < num_flines; i++)
886 fprintf(fp, "%s", flines[i]);
887 fclose(fp);
888 buffer_print();
889 }
890 else
891 printf("%sNo log file%s", HIGHLIGHT, NORMAL);
892}
893
894#ifdef CONFIG_FEATURE_LESS_MARKS
895static void add_mark(void) {
896
897 int letter;
898 int mark_line;
899
900 clear_line();
901 printf("Mark: ");
902 letter = tless_getch();
903
904 if (isalpha(letter)) {
905 mark_line = line_pos;
906
907 /* If we exceed 15 marks, start overwriting previous ones */
908 if (num_marks == 14)
909 num_marks = 0;
910
911 mark_lines[num_marks][0] = letter;
912 mark_lines[num_marks][1] = line_pos;
913 num_marks++;
914 }
915 else {
916 clear_line();
917 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
918 }
919}
920
921static void goto_mark(void) {
922
923 int letter;
924 int i;
925
926 clear_line();
927 printf("Go to mark: ");
928 letter = tless_getch();
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000929 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000930
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000931 if (isalpha(letter)) {
932 for (i = 0; i <= num_marks; i++)
933 if (letter == mark_lines[i][0]) {
934 buffer_line(mark_lines[i][1]);
935 break;
936 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000937 if ((num_marks == 14) && (letter != mark_lines[14][0]))
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000938 printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000939 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000940 else
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000941 printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000942}
943#endif
944
945
946#ifdef CONFIG_FEATURE_LESS_BRACKETS
947
948static char opp_bracket (char bracket) {
949
950 switch (bracket) {
951 case '{': case '[':
952 return bracket + 2;
953 break;
954 case '(':
955 return ')';
956 break;
957 case '}': case ']':
958 return bracket - 2;
959 break;
960 case ')':
961 return '(';
962 break;
963 default:
964 return 0;
965 break;
966 }
967}
968
969static void match_right_bracket(char bracket) {
970
971 int bracket_line = -1;
972 int i;
973
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000974 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +0000975
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000976 if (strchr(flines[line_pos], bracket) == NULL)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000977 printf("%s%s%s", HIGHLIGHT, "No bracket in top line", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000978 else {
979 for (i = line_pos + 1; i < num_flines; i++) {
980 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
981 bracket_line = i;
982 break;
983 }
984 }
985
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000986 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000987 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +0000988
989 buffer_line(bracket_line - height + 2);
990 buffer_print();
991 }
992}
993
994static void match_left_bracket (char bracket) {
995
996 int bracket_line = -1;
997 int i;
998
Rob Landleyd57ae8b2005-09-18 00:58:49 +0000999 clear_line();
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +00001000
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001001 if (strchr(flines[line_pos + height - 2], bracket) == NULL) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001002 printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL);
1003 printf("%s", flines[line_pos + height]);
1004 sleep(4);
1005 }
1006 else {
1007 for (i = line_pos + height - 2; i >= 0; i--) {
1008 if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
1009 bracket_line = i;
1010 break;
1011 }
1012 }
1013
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001014 if (bracket_line == -1)
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001015 printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001016
1017 buffer_line(bracket_line);
1018 buffer_print();
1019 }
1020}
1021
1022#endif /* CONFIG_FEATURE_LESS_BRACKETS */
1023
Rob Landley9200e792005-09-15 19:26:59 +00001024static void keypress_process(int keypress) {
1025 switch (keypress) {
1026 case KEY_DOWN: case 'e': case 'j': case '\015':
1027 buffer_down(1);
1028 buffer_print();
1029 break;
1030 case KEY_UP: case 'y': case 'k':
1031 buffer_up(1);
1032 buffer_print();
1033 break;
1034 case PAGE_DOWN: case ' ': case 'z':
1035 buffer_down(height - 1);
1036 buffer_print();
1037 break;
1038 case PAGE_UP: case 'w': case 'b':
1039 buffer_up(height - 1);
1040 buffer_print();
1041 break;
1042 case 'd':
1043 buffer_down((height - 1) / 2);
1044 buffer_print();
1045 break;
1046 case 'u':
1047 buffer_up((height - 1) / 2);
1048 buffer_print();
1049 break;
1050 case 'g': case 'p': case '<': case '%':
1051 buffer_up(num_flines + 1);
1052 buffer_print();
1053 break;
1054 case 'G': case '>':
1055 buffer_down(num_flines + 1);
1056 buffer_print();
1057 break;
1058 case 'q': case 'Q':
1059 tless_exit(0);
1060 break;
1061#ifdef CONFIG_FEATURE_LESS_MARKS
1062 case 'm':
1063 add_mark();
1064 buffer_print();
1065 break;
1066 case '\'':
1067 goto_mark();
1068 buffer_print();
1069 break;
1070#endif
1071 case 'r':
1072 buffer_print();
1073 break;
1074 case 'R':
1075 full_repaint();
1076 break;
1077 case 's':
1078 if (inp_stdin)
1079 save_input_to_file();
1080 break;
1081 case 'E':
1082 examine_file();
1083 break;
1084#ifdef CONFIG_FEATURE_LESS_FLAGS
1085 case '=':
1086 clear_line();
1087 m_status_print();
1088 break;
1089#endif
1090#ifdef CONFIG_FEATURE_LESS_REGEXP
1091 case '/':
1092 regex_process();
1093 buffer_print();
1094 break;
1095 case 'n':
1096 goto_match(match_pos + 1);
1097 buffer_print();
1098 break;
1099 case 'N':
1100 goto_match(match_pos - 1);
1101 buffer_print();
1102 break;
1103 case '?':
1104 search_backwards();
1105 buffer_print();
1106 break;
1107#endif
1108#ifdef CONFIG_FEATURE_LESS_FLAGCS
1109 case '-':
1110 flag_change();
1111 buffer_print();
1112 break;
1113 case '_':
1114 show_flag_status();
1115 break;
1116#endif
1117#ifdef CONFIG_FEATURE_LESS_BRACKETS
1118 case '{': case '(': case '[':
1119 match_right_bracket(keypress);
1120 break;
1121 case '}': case ')': case ']':
1122 match_left_bracket(keypress);
1123 break;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001124#endif
1125 case ':':
Rob Landley9200e792005-09-15 19:26:59 +00001126 colon_process();
1127 break;
1128 default:
1129 break;
1130 }
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001131
Rob Landley9200e792005-09-15 19:26:59 +00001132 if (isdigit(keypress))
1133 number_process(keypress);
1134}
1135
Rob Landley9200e792005-09-15 19:26:59 +00001136int less_main(int argc, char **argv) {
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001137
Rob Landley9200e792005-09-15 19:26:59 +00001138 int keypress;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001139
Rob Landleyd57ae8b2005-09-18 00:58:49 +00001140 flags = bb_getopt_ulflags(argc, argv, "EMmN~");
Rob Landley9200e792005-09-15 19:26:59 +00001141
1142 argc -= optind;
1143 argv += optind;
1144 files = argv;
1145 num_files = argc;
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001146
Rob Landley9200e792005-09-15 19:26:59 +00001147 if (!num_files) {
1148 if (ttyname(STDIN_FILENO) == NULL)
1149 inp_stdin = 1;
1150 else {
1151 bb_error_msg("Missing filename");
1152 bb_show_usage();
1153 }
1154 }
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001155
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +00001156 strcpy(filename, (inp_stdin) ? bb_msg_standard_input : files[0]);
Rob Landley9200e792005-09-15 19:26:59 +00001157 tty_width_height();
"Vladimir N. Oleynik"bc374802005-09-19 14:23:46 +00001158 data_readlines();
1159 tcgetattr(fileno(inp), &term_orig);
"Vladimir N. Oleynik"a0ae6de2005-09-19 10:28:43 +00001160 term_vi = term_orig;
1161 term_vi.c_lflag &= (~ICANON & ~ECHO);
1162 term_vi.c_iflag &= (~IXON & ~ICRNL);
1163 term_vi.c_oflag &= (~ONLCR);
1164 term_vi.c_cc[VMIN] = 1;
1165 term_vi.c_cc[VTIME] = 0;
Rob Landley9200e792005-09-15 19:26:59 +00001166 buffer_init();
1167 buffer_print();
"Vladimir N. Oleynik"2b306e92005-09-16 12:32:22 +00001168
Rob Landley9200e792005-09-15 19:26:59 +00001169 while (1) {
1170 keypress = tless_getch();
1171 keypress_process(keypress);
1172 }
1173}