* This program needs a lot of development, so consider it in a beta stage
* at best.
*
- * TODO:
+ * TODO:
* - Add more regular expression support - search modifiers, certain matches, etc.
* - Add more complex bracket searching - currently, nested brackets are
* not considered.
#include <string.h>
#include <termios.h>
#include <unistd.h>
-#include <regex.h>
#include <ctype.h>
+
#include "busybox.h"
+#ifdef CONFIG_FEATURE_LESS_REGEXP
+#include "xregex.h"
+#endif
+
+
/* These are the escape sequences corresponding to special keys */
#define REAL_KEY_UP 'A'
#define REAL_KEY_DOWN 'B'
#define MAXLINES 10000
/* Get height and width of terminal */
-#define tty_width_height() get_terminal_width_height(0, &width, &height)
-
-/* Function prototypes */
-static void set_tty_cooked(void);
-static void set_tty_raw(void);
-static void tless_exit(int code);
-static int tless_getch(void);
-static void move_cursor(int x, int y);
-static void clear_line(void);
-static void data_readlines(void);
-static void free_flines(void);
-#ifdef CONFIG_FEATURE_LESS_FLAGS
-static int calc_percent(void);
-#endif
-static int reverse_percent(int percentage);
-#ifdef CONFIG_FEATURE_LESS_FLAGS
-static void m_status_print(void);
-static void medium_status_print(void);
-#endif
-static void status_print(void);
-static void buffer_print(void);
-static void buffer_init(void);
-static void buffer_down(int nlines);
-static void buffer_up(int nlines);
-static void buffer_line(int linenum);
-static void keypress_process(int keypress);
-static void colon_process(void);
-static void number_process(int first_digit);
-#ifdef CONFIG_FEATURE_LESS_FLAGCS
-static void flag_change(void);
-static void show_flag_status(void);
-#endif
-static void examine_file(void);
-static void next_file(void);
-static void previous_file(void);
-static void first_file(void);
-static void remove_current_file(void);
-static void full_repaint(void);
-static void add_linenumbers(void);
-static void save_input_to_file(void);
-#ifdef CONFIG_FEATURE_LESS_MARKS
-static void add_mark(void);
-static void goto_mark(void);
-#endif
-#ifdef CONFIG_FEATURE_LESS_REGEXP
-static void regex_process(void);
-char *process_regex_on_line(char *line, regex_t *pattern);
-char *insert_highlights(char *line, int start, int end);
-static void goto_match (int match);
-static void search_backwards(void);
-#endif
-#ifdef CONFIG_FEATURE_LESS_BRACKETS
-static char opp_bracket (char bracket);
-static void match_right_bracket (char bracket);
-static void match_left_bracket (char bracket);
-#endif
-int less_main(int argc, char *argv[]);
+#define tty_width_height() get_terminal_width_height(0, &width, &height)
static int height;
static int width;
static char buffer[100][256];
static char *flines[MAXLINES];
static int current_file = 1;
-static int line_pos = 0;
+static int line_pos;
static int num_flines;
static int num_files = 1;
-static int past_eof = 0;
+static int past_eof;
/* Command line options */
-static int E_FLAG = 0;
-static int M_FLAG = 0;
-static int N_FLAG = 0;
-static int m_FLAG = 0;
-static int TILDE_FLAG = 0;
+static int E_FLAG;
+static int M_FLAG;
+static int N_FLAG;
+static int m_FLAG;
+static int TILDE_FLAG;
/* This is needed so that program behaviour changes when input comes from
stdin */
-static int inp_stdin = 0;
+static int inp_stdin;
/* This is required so that when a file is requested to be examined after
- input has come from stdin (e.g. dmesg | less), the input stream from
+ input has come from stdin (e.g. dmesg | less), the input stream from
the keyboard still stays the same. If it switched back to stdin, keyboard
input wouldn't work. */
-static int ea_inp_stdin = 0;
+static int ea_inp_stdin;
#ifdef CONFIG_FEATURE_LESS_MARKS
static int mark_lines[15][2];
-static int num_marks = 0;
+static int num_marks;
#endif
#ifdef CONFIG_FEATURE_LESS_REGEXP
-static int match_found = 0;
+static int match_found;
static int match_lines[100];
-static int match_pos = 0;
-static int num_matches = 0;
-static int match_backwards = 0;
+static int match_pos;
+static int num_matches;
+static int match_backwards;
static int num_back_match = 1;
#endif
static FILE *inp;
/* Reset terminal input to normal */
-static void set_tty_cooked() {
- fflush(stdout);
- tcsetattr(0, TCSANOW, &term_orig);
+static void set_tty_cooked(void) {
+ fflush(stdout);
+ tcsetattr(0, TCSANOW, &term_orig);
}
/* Set terminal input to raw mode */
-static void set_tty_raw() {
+static void set_tty_raw(void) {
tcgetattr(0, &term_orig);
- term_vi = term_orig;
- term_vi.c_lflag &= (~ICANON & ~ECHO);
- term_vi.c_iflag &= (~IXON & ~ICRNL);
- term_vi.c_oflag &= (~ONLCR);
- term_vi.c_cc[VMIN] = 1;
- term_vi.c_cc[VTIME] = 0;
- tcsetattr(0, TCSANOW, &term_vi);
+ term_vi = term_orig;
+ term_vi.c_lflag &= (~ICANON & ~ECHO);
+ term_vi.c_iflag &= (~IXON & ~ICRNL);
+ term_vi.c_oflag &= (~ONLCR);
+ term_vi.c_cc[VMIN] = 1;
+ term_vi.c_cc[VTIME] = 0;
+ tcsetattr(0, TCSANOW, &term_vi);
}
/* Exit the program gracefully */
static void tless_exit(int code) {
-
+
/* TODO: We really should save the terminal state when we start,
- and restore it when we exit. Less does this with the
+ and restore it when we exit. Less does this with the
"ti" and "te" termcap commands; can this be done with
only termios.h? */
-
+
putchar('\n');
exit(code);
}
/* Grab a character from input without requiring the return key. If the
character is ASCII \033, get more characters and assign certain sequences
- special return codes. Note that this function works best with raw input. */
-int tless_getch() {
-
+ special return codes. Note that this function works best with raw input. */
+static int tless_getch(void) {
+
set_tty_raw();
char input_key[3];
-
+
input_key[0] = getc(inp);
/* Detect escape sequences (i.e. arrow keys) and handle
them accordingly */
-
+
if (input_key[0] == '\033') {
input_key[1] = getc(inp);
input_key[2] = getc(inp);
return 0;
}
-/* Move the cursor to a position (x,y), where (0,0) is the
+/* Move the cursor to a position (x,y), where (0,0) is the
top-left corner of the console */
static void move_cursor(int x, int y) {
printf("\033[%i;%iH", x, y);
}
-static void clear_line() {
+static void clear_line(void) {
move_cursor(height, 0);
printf("\033[K");
}
-static void data_readlines() {
-
+/* This adds line numbers to every line, as the -N flag necessitates */
+static void add_linenumbers(void) {
+
+ char current_line[256];
+ int i;
+
+ for (i = 0; i <= num_flines; i++) {
+ safe_strncpy(current_line, flines[i], 256);
+ flines[i] = xrealloc(flines[i], strlen(current_line) + 7 );
+ sprintf(flines[i],"%5d %s", i+1, current_line);
+ }
+}
+
+static void data_readlines(void) {
+
int i;
char current_line[256];
FILE *fp;
-
+
fp = (inp_stdin) ? stdin : bb_xfopen(filename, "rt");
-
+
for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++) {
strcpy(current_line, "");
fgets(current_line, 256, fp);
num_flines = i - 2;
/* Reset variables for a new file */
-
+
line_pos = 0;
past_eof = 0;
-
+
fclose(fp);
if (inp_stdin)
fclose(inp);
inp = fopen(CURRENT_TTY, "r");
}
-
+
if (N_FLAG)
add_linenumbers();
}
/* Free the file data */
-static void free_flines() {
-
+static void free_flines(void) {
+
int i;
-
+
for (i = 0; i <= num_flines; i++)
free(flines[i]);
}
#ifdef CONFIG_FEATURE_LESS_FLAGS
/* Calculate the percentage the current line position is through the file */
-int calc_percent() {
+static int calc_percent(void) {
return ((100 * (line_pos + height - 2) / num_flines) + 1);
}
#endif
/* Turn a percentage into a line number */
-int reverse_percent(int percentage) {
+static int reverse_percent(int percentage) {
double linenum = percentage;
linenum = ((linenum / 100) * num_flines) - 1;
return(linenum);
#ifdef CONFIG_FEATURE_LESS_FLAGS
/* Print a status line if -M was specified */
-static void m_status_print() {
+static void m_status_print(void) {
int percentage;
-
+
if (!past_eof) {
if (!line_pos) {
if (num_files > 1)
else {
printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename, line_pos + 1, line_pos + height - 1, num_flines + 1);
}
-
+
if (line_pos == num_flines - height + 2) {
printf("(END) %s", NORMAL);
if ((num_files > 1) && (current_file != num_files))
}
/* Print a status line if -m was specified */
-static void medium_status_print() {
+static void medium_status_print(void) {
int percentage;
percentage = calc_percent();
-
+
if (!line_pos)
printf("%s%s %i%s%s", HIGHLIGHT, filename, percentage, "%", NORMAL);
else if (line_pos == num_flines - height + 2)
#endif
/* Print the status line */
-static void status_print() {
-
+static void status_print(void) {
+
/* Change the status if flags have been set */
-#ifdef CONFIG_FEATURE_LESS_FLAGS
- if (M_FLAG)
+#ifdef CONFIG_FEATURE_LESS_FLAGS
+ if (M_FLAG)
m_status_print();
else if (m_FLAG)
medium_status_print();
}
/* Print the buffer */
-static void buffer_print() {
-
+static void buffer_print(void) {
+
int i;
-
+
if (num_flines >= height - 2) {
printf("%s", CLEAR);
move_cursor(0,0);
}
/* Initialise the buffer */
-static void buffer_init() {
-
+static void buffer_init(void) {
+
int i;
-
+
for (i = 0; i < (height - 1); i++)
memset(buffer[i], '\0', 256);
-
- /* Fill the buffer until the end of the file or the
+
+ /* Fill the buffer until the end of the file or the
end of the buffer is reached */
for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) {
strcpy(buffer[i], flines[i]);
}
-
+
/* If the buffer still isn't full, fill it with blank lines */
for (; i < (height - 1); i++) {
strcpy(buffer[i], "");
/* Move the buffer up and down in the file in order to scroll */
static void buffer_down(int nlines) {
-
+
int i;
-
+
if (!past_eof) {
if (line_pos + (height - 3) + nlines < num_flines) {
line_pos += nlines;
}
else {
/* As the number of lines requested was too large, we just move
- to the end of the file */
- while (line_pos + (height - 3) + 1 < num_flines) {
+ to the end of the file */
+ while (line_pos + (height - 3) + 1 < num_flines) {
line_pos += 1;
for (i = 0; i < (height - 1); i++)
strcpy(buffer[i], flines[line_pos + i]);
}
static void buffer_up(int nlines) {
-
+
int i;
int tilde_line;
-
+
if (!past_eof) {
if (line_pos - nlines >= 0) {
line_pos -= nlines;
else {
/* Work out where the tildes start */
tilde_line = num_flines - line_pos + 3;
-
+
line_pos -= nlines;
/* Going backwards nlines lines has taken us to a point where
nothing is past the EOF, so we revert to normal. */
}
else {
/* We only move part of the buffer, as the rest
- is past the EOF */
+ is past the EOF */
for (i = 0; i < (height - 1); i++) {
if (i < tilde_line - nlines + 1)
strcpy(buffer[i], flines[line_pos + i]);
strcpy(buffer[i], "~\n");
}
}
- }
+ }
}
}
static void buffer_line(int linenum) {
-
+
int i;
past_eof = 0;
}
}
-static void keypress_process(int keypress) {
- switch (keypress) {
- case KEY_DOWN: case 'e': case 'j': case '\015':
- buffer_down(1);
- buffer_print();
- break;
- case KEY_UP: case 'y': case 'k':
- buffer_up(1);
- buffer_print();
- break;
- case PAGE_DOWN: case ' ': case 'z':
- buffer_down(height - 1);
- buffer_print();
- break;
- case PAGE_UP: case 'w': case 'b':
- buffer_up(height - 1);
- buffer_print();
- break;
- case 'd':
- buffer_down((height - 1) / 2);
- buffer_print();
- break;
- case 'u':
- buffer_up((height - 1) / 2);
- buffer_print();
- break;
- case 'g': case 'p': case '<': case '%':
- buffer_up(num_flines + 1);
- buffer_print();
- break;
- case 'G': case '>':
- buffer_down(num_flines + 1);
- buffer_print();
- break;
- case 'q': case 'Q':
- tless_exit(0);
- break;
-#ifdef CONFIG_FEATURE_LESS_MARKS
- case 'm':
- add_mark();
- buffer_print();
- break;
- case '\'':
- goto_mark();
- buffer_print();
- break;
-#endif
- case 'r':
- buffer_print();
- break;
- case 'R':
- full_repaint();
- break;
- case 's':
- if (inp_stdin)
- save_input_to_file();
- break;
- case 'E':
- examine_file();
- break;
-#ifdef CONFIG_FEATURE_LESS_FLAGS
- case '=':
- clear_line();
- m_status_print();
- break;
-#endif
-#ifdef CONFIG_FEATURE_LESS_REGEXP
- case '/':
- regex_process();
- buffer_print();
- break;
- case 'n':
- goto_match(match_pos + 1);
- buffer_print();
- break;
- case 'N':
- goto_match(match_pos - 1);
- buffer_print();
- break;
- case '?':
- search_backwards();
- buffer_print();
- break;
-#endif
-#ifdef CONFIG_FEATURE_LESS_FLAGCS
- case '-':
- flag_change();
- buffer_print();
- break;
- case '_':
- show_flag_status();
- break;
-#endif
-#ifdef CONFIG_FEATURE_LESS_BRACKETS
- case '{': case '(': case '[':
- match_right_bracket(keypress);
- break;
- case '}': case ')': case ']':
- match_left_bracket(keypress);
- break;
-#endif
- case ':':
- colon_process();
- break;
- default:
- break;
+static void examine_file(void) {
+
+ int newline_offset;
+
+ clear_line();
+ printf("Examine: ");
+ fgets(filename, 256, inp);
+
+ /* As fgets adds a newline to the end of an input string, we
+ need to remove it */
+ newline_offset = strlen(filename) - 1;
+ filename[newline_offset] = '\0';
+
+ files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
+ current_file = num_files + 1;
+ num_files++;
+
+ inp_stdin = 0;
+ ea_inp_stdin = 1;
+ free_flines();
+ data_readlines();
+ buffer_init();
+ buffer_print();
+}
+
+
+static void next_file(void) {
+ if (current_file != num_files) {
+ current_file++;
+ strcpy(filename, files[current_file - 1]);
+ free_flines();
+ data_readlines();
+ buffer_init();
+ buffer_print();
+ }
+ else {
+ clear_line();
+ printf("%s%s%s", HIGHLIGHT, "No next file", NORMAL);
+ }
+}
+
+static void previous_file(void) {
+ if (current_file != 1) {
+ current_file--;
+ strcpy(filename, files[current_file - 1]);
+
+ free_flines();
+ data_readlines();
+ buffer_init();
+ buffer_print();
+ }
+ else {
+ clear_line();
+ printf("%s%s%s", HIGHLIGHT, "No previous file", NORMAL);
+ }
+}
+
+static void first_file(void) {
+ if (current_file != 1) {
+ current_file = 1;
+ strcpy(filename, files[current_file - 1]);
+ free_flines();
+ data_readlines();
+ buffer_init();
+ buffer_print();
+ }
+}
+
+static void remove_current_file(void) {
+
+ int i;
+
+ if (current_file != 1) {
+ previous_file();
+ for (i = 3; i <= num_files; i++)
+ files[i - 2] = files[i - 1];
+ num_files--;
+ buffer_print();
+ }
+ else {
+ next_file();
+ for (i = 2; i <= num_files; i++)
+ files[i - 2] = files[i - 1];
+ num_files--;
+ current_file--;
+ buffer_print();
}
- if (isdigit(keypress))
- number_process(keypress);
}
-static void colon_process() {
-
+static void colon_process(void) {
+
int keypress;
-
+
/* Clear the current line and print a prompt */
clear_line();
printf(" :");
-
+
keypress = tless_getch();
switch (keypress) {
case 'd':
}
}
-static void number_process(int first_digit) {
-
- int i = 1;
- int num;
- char num_input[80];
- char keypress;
- num_input[0] = first_digit;
-
- /* Clear the current line, print a prompt, and then print the digit */
+#ifdef CONFIG_FEATURE_LESS_REGEXP
+/* The below two regular expression handler functions NEED development. */
+
+/* Get a regular expression from the user, and then go through the current
+ file line by line, running a processing regex function on each one. */
+
+static char *insert_highlights (char *line, int start, int end) {
+
+ char *new_line = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 10);
+
+ memset(new_line, 0, ((sizeof(char) * (strlen(line) + 1)) + 10));
+ strncat(new_line, line, start);
+ strcat(new_line, HIGHLIGHT);
+ strncat(new_line, line + start, end - start);
+ strcat(new_line, NORMAL);
+ strncat(new_line, line + end, strlen(line) - end);
+
+ return new_line;
+}
+
+static char *process_regex_on_line(char *line, regex_t *pattern) {
+ /* This function takes the regex and applies it to the line.
+ Each part of the line that matches has the HIGHLIGHT
+ and NORMAL escape sequences placed around it by
+ insert_highlights, and then the line is returned. */
+
+ int match_status;
+ char *line2 = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 64);
+ char sub_line[256];
+ int prev_eo = 0;
+ memset(sub_line, 0, 256);
+ strcpy(line2, line);
+ regmatch_t match_structs;
+
+ match_found = 0;
+ match_status = regexec(pattern, line2, 1, &match_structs, 0);
+
+ while (match_status == 0) {
+
+ memset(sub_line, 0, 256);
+
+ if (match_found == 0)
+ match_found = 1;
+
+ line2 = insert_highlights(line2, match_structs.rm_so + prev_eo, match_structs.rm_eo + prev_eo);
+ if (match_structs.rm_eo + 11 + prev_eo < strlen(line2))
+ strcat(sub_line, line2 + match_structs.rm_eo + 11 + prev_eo);
+
+ prev_eo += match_structs.rm_eo + 11;
+ match_status = regexec(pattern, sub_line, 1, &match_structs, REG_NOTBOL);
+ }
+
+ return line2;
+}
+
+static void regex_process(void) {
+
+ char uncomp_regex[100];
+ char current_line[256];
+ int i;
+ int j = 0;
+ regex_t *pattern;
+
+ /* Reset variables */
+ match_lines[0] = -1;
+ match_pos = 0;
+ num_matches = 0;
+ match_found = 0;
+
+ pattern = (regex_t *) malloc(sizeof(regex_t));
+ memset(pattern, 0, sizeof(regex_t));
+
+ /* Get the uncompiled regular expression from the user */
+ clear_line();
+ if (match_backwards)
+ printf("?");
+ else
+ printf("/");
+ scanf("%s", uncomp_regex);
+
+ /* Compile the regex and check for errors */
+ xregcomp(pattern, uncomp_regex, 0);
+
+ /* Run the regex on each line of the current file here */
+ for (i = 0; i <= num_flines; i++) {
+ strcpy(current_line, process_regex_on_line(flines[i], pattern));
+ flines[i] = (char *) bb_xstrndup(current_line, sizeof(char) * (strlen(current_line)+1));
+
+ if (match_found) {
+ match_lines[j] = i;
+ j++;
+ }
+ }
+
+ num_matches = j;
+
+ if ((match_lines[0] != -1) && (num_flines > height - 2))
+ buffer_line(match_lines[0]);
+ else
+ buffer_init();
+}
+
+static void goto_match(int match) {
+
+ /* This goes to a specific match - all line positions of matches are
+ stored within the match_lines[] array. */
+ if ((match < num_matches) && (match >= 0)) {
+ buffer_line(match_lines[match]);
+ match_pos = match;
+ }
+}
+
+static void search_backwards(void) {
+
+ int current_linepos = line_pos;
+ int i;
+
+ match_backwards = 1;
+ regex_process();
+
+ for (i = 0; i < num_matches; i++) {
+ if (match_lines[i] > current_linepos) {
+ buffer_line(match_lines[i - num_back_match]);
+ break;
+ }
+ }
+
+ /* Reset variables */
+ match_backwards = 0;
+ num_back_match = 1;
+
+}
+#endif
+
+static void number_process(int first_digit) {
+
+ int i = 1;
+ int num;
+ char num_input[80];
+ char keypress;
+ num_input[0] = first_digit;
+
+ /* Clear the current line, print a prompt, and then print the digit */
clear_line();
printf(":%c", first_digit);
-
+
/* Receive input until a letter is given */
while((num_input[i] = tless_getch()) && isdigit(num_input[i])) {
printf("%c",num_input[i]);
i++;
}
-
+
/* Take the final letter out of the digits string */
keypress = num_input[i];
num_input[i] = '\0';
}
#ifdef CONFIG_FEATURE_LESS_FLAGCS
-static void flag_change() {
-
+static void flag_change(void) {
+
int keypress;
-
+
clear_line();
printf("-");
keypress = tless_getch();
-
+
switch (keypress) {
case 'M':
M_FLAG = !M_FLAG;
}
}
-static void show_flag_status() {
-
+static void show_flag_status(void) {
+
int keypress;
int flag_val;
-
+
clear_line();
printf("_");
keypress = tless_getch();
flag_val = 0;
break;
}
-
- clear_line();
- printf("%s%s%i%s", HIGHLIGHT, "The status of the flag is: ", flag_val, NORMAL);
-}
-#endif
-static void examine_file() {
-
- int newline_offset;
-
clear_line();
- printf("Examine: ");
- fgets(filename, 256, inp);
-
- /* As fgets adds a newline to the end of an input string, we
- need to remove it */
- newline_offset = strlen(filename) - 1;
- filename[newline_offset] = '\0';
-
- files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
- current_file = num_files + 1;
- num_files++;
-
- inp_stdin = 0;
- ea_inp_stdin = 1;
- free_flines();
- data_readlines();
- buffer_init();
- buffer_print();
-}
-
-static void next_file() {
- if (current_file != num_files) {
- current_file++;
- strcpy(filename, files[current_file - 1]);
- free_flines();
- data_readlines();
- buffer_init();
- buffer_print();
- }
- else {
- clear_line();
- printf("%s%s%s", HIGHLIGHT, "No next file", NORMAL);
- }
-}
-
-static void previous_file() {
- if (current_file != 1) {
- current_file--;
- strcpy(filename, files[current_file - 1]);
-
- free_flines();
- data_readlines();
- buffer_init();
- buffer_print();
- }
- else {
- clear_line();
- printf("%s%s%s", HIGHLIGHT, "No previous file", NORMAL);
- }
-}
-
-static void first_file() {
- if (current_file != 1) {
- current_file = 1;
- strcpy(filename, files[current_file - 1]);
- free_flines();
- data_readlines();
- buffer_init();
- buffer_print();
- }
-}
-
-static void remove_current_file() {
-
- int i;
-
- if (current_file != 1) {
- previous_file();
- for (i = 3; i <= num_files; i++)
- files[i - 2] = files[i - 1];
- num_files--;
- buffer_print();
- }
- else {
- next_file();
- for (i = 2; i <= num_files; i++)
- files[i - 2] = files[i - 1];
- num_files--;
- current_file--;
- buffer_print();
- }
+ printf("%s%s%i%s", HIGHLIGHT, "The status of the flag is: ", flag_val != 0, NORMAL);
}
+#endif
-static void full_repaint() {
+static void full_repaint(void) {
int temp_line_pos = line_pos;
data_readlines();
buffer_print();
}
-/* This adds line numbers to every line, as the -N flag necessitates */
-static void add_linenumbers() {
- char current_line[256];
- int i;
-
- for (i = 0; i <= num_flines; i++) {
- safe_strncpy(current_line, flines[i], 256);
- flines[i] = xrealloc(flines[i], strlen(current_line) + 7 );
- sprintf(flines[i],"%5d %s", i+1, current_line);
- }
-}
+static void save_input_to_file(void) {
-static void save_input_to_file() {
-
char current_line[256];
int i;
FILE *fp;
-
+
clear_line();
printf("Log file: ");
fgets(current_line, 256, inp);
}
#ifdef CONFIG_FEATURE_LESS_MARKS
-static void add_mark() {
+static void add_mark(void) {
int letter;
int mark_line;
-
+
clear_line();
printf("Mark: ");
letter = tless_getch();
-
+
if (isalpha(letter)) {
mark_line = line_pos;
-
+
/* If we exceed 15 marks, start overwriting previous ones */
if (num_marks == 14)
num_marks = 0;
}
}
-static void goto_mark() {
+static void goto_mark(void) {
int letter;
int i;
-
+
clear_line();
printf("Go to mark: ");
letter = tless_getch();
if ((num_marks == 14) && (letter != mark_lines[14][0])) {
clear_line();
printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL);
- }
+ }
}
else {
clear_line();
}
#endif
-#ifdef CONFIG_FEATURE_LESS_REGEXP
-/* The below two regular expression handler functions NEED development. */
-
-/* Get a regular expression from the user, and then go through the current
- file line by line, running a processing regex function on each one. */
-static void regex_process() {
-
- char uncomp_regex[100];
- char current_line[256];
- int i;
- int j = 0;
- regex_t *pattern;
-
- /* Reset variables */
- match_lines[0] = -1;
- match_pos = 0;
- num_matches = 0;
- match_found = 0;
-
- pattern = (regex_t *) malloc(sizeof(regex_t));
- memset(pattern, 0, sizeof(regex_t));
-
- /* Get the uncompiled regular expression from the user */
- clear_line();
- if (match_backwards)
- printf("?");
- else
- printf("/");
- scanf("%s", uncomp_regex);
-
- /* Compile the regex and check for errors */
- xregcomp(pattern, uncomp_regex, 0);
-
- /* Run the regex on each line of the current file here */
- for (i = 0; i <= num_flines; i++) {
- strcpy(current_line, process_regex_on_line(flines[i], pattern));
- flines[i] = (char *) bb_xstrndup(current_line, sizeof(char) * (strlen(current_line)+1));
-
- if (match_found) {
- match_lines[j] = i;
- j++;
- }
- }
-
- num_matches = j;
-
- if ((match_lines[0] != -1) && (num_flines > height - 2))
- buffer_line(match_lines[0]);
- else
- buffer_init();
-}
-
-char *process_regex_on_line(char *line, regex_t *pattern) {
- /* This function takes the regex and applies it to the line.
- Each part of the line that matches has the HIGHLIGHT
- and NORMAL escape sequences placed around it by
- insert_highlights, and then the line is returned. */
-
- int match_status;
- char *line2 = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 64);
- char sub_line[256];
- int prev_eo = 0;
- memset(sub_line, 0, 256);
- strcpy(line2, line);
- regmatch_t match_structs;
-
- match_found = 0;
- match_status = regexec(pattern, line2, 1, &match_structs, 0);
-
- while (match_status == 0) {
-
- memset(sub_line, 0, 256);
-
- if (match_found == 0)
- match_found = 1;
-
- line2 = insert_highlights(line2, match_structs.rm_so + prev_eo, match_structs.rm_eo + prev_eo);
- if (match_structs.rm_eo + 11 + prev_eo < strlen(line2))
- strcat(sub_line, line2 + match_structs.rm_eo + 11 + prev_eo);
-
- prev_eo += match_structs.rm_eo + 11;
- match_status = regexec(pattern, sub_line, 1, &match_structs, REG_NOTBOL);
- }
-
- return line2;
-}
-
-char *insert_highlights (char *line, int start, int end) {
-
- char *new_line = (char *) malloc((sizeof(char) * (strlen(line) + 1)) + 10);
- memset(new_line, 0, ((sizeof(char) * (strlen(line) + 1)) + 10));
- strncat(new_line, line, start);
- strcat(new_line, HIGHLIGHT);
- strncat(new_line, line + start, end - start);
- strcat(new_line, NORMAL);
- strncat(new_line, line + end, strlen(line) - end);
-
- return new_line;
-}
-
-static void goto_match(int match) {
-
- /* This goes to a specific match - all line positions of matches are
- stored within the match_lines[] array. */
- if ((match < num_matches) && (match >= 0)) {
- buffer_line(match_lines[match]);
- match_pos = match;
- }
-}
-
-static void search_backwards() {
-
- int current_linepos = line_pos;
- int i;
-
- match_backwards = 1;
- regex_process();
-
- for (i = 0; i < num_matches; i++) {
- if (match_lines[i] > current_linepos) {
- buffer_line(match_lines[i - num_back_match]);
- break;
- }
- }
-
- /* Reset variables */
- match_backwards = 0;
- num_back_match = 1;
-
-}
-#endif
#ifdef CONFIG_FEATURE_LESS_BRACKETS
}
static void match_right_bracket(char bracket) {
-
+
int bracket_line = -1;
int i;
-
+
if (strchr(flines[line_pos], bracket) == NULL) {
clear_line();
printf("%s%s%s", HIGHLIGHT, "No bracket in top line", NORMAL);
}
static void match_left_bracket (char bracket) {
-
+
int bracket_line = -1;
int i;
clear_line();
printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
}
-
+
buffer_line(bracket_line);
buffer_print();
}
}
+#endif /* CONFIG_FEATURE_LESS_BRACKETS */
+
+static void keypress_process(int keypress) {
+ switch (keypress) {
+ case KEY_DOWN: case 'e': case 'j': case '\015':
+ buffer_down(1);
+ buffer_print();
+ break;
+ case KEY_UP: case 'y': case 'k':
+ buffer_up(1);
+ buffer_print();
+ break;
+ case PAGE_DOWN: case ' ': case 'z':
+ buffer_down(height - 1);
+ buffer_print();
+ break;
+ case PAGE_UP: case 'w': case 'b':
+ buffer_up(height - 1);
+ buffer_print();
+ break;
+ case 'd':
+ buffer_down((height - 1) / 2);
+ buffer_print();
+ break;
+ case 'u':
+ buffer_up((height - 1) / 2);
+ buffer_print();
+ break;
+ case 'g': case 'p': case '<': case '%':
+ buffer_up(num_flines + 1);
+ buffer_print();
+ break;
+ case 'G': case '>':
+ buffer_down(num_flines + 1);
+ buffer_print();
+ break;
+ case 'q': case 'Q':
+ tless_exit(0);
+ break;
+#ifdef CONFIG_FEATURE_LESS_MARKS
+ case 'm':
+ add_mark();
+ buffer_print();
+ break;
+ case '\'':
+ goto_mark();
+ buffer_print();
+ break;
#endif
+ case 'r':
+ buffer_print();
+ break;
+ case 'R':
+ full_repaint();
+ break;
+ case 's':
+ if (inp_stdin)
+ save_input_to_file();
+ break;
+ case 'E':
+ examine_file();
+ break;
+#ifdef CONFIG_FEATURE_LESS_FLAGS
+ case '=':
+ clear_line();
+ m_status_print();
+ break;
+#endif
+#ifdef CONFIG_FEATURE_LESS_REGEXP
+ case '/':
+ regex_process();
+ buffer_print();
+ break;
+ case 'n':
+ goto_match(match_pos + 1);
+ buffer_print();
+ break;
+ case 'N':
+ goto_match(match_pos - 1);
+ buffer_print();
+ break;
+ case '?':
+ search_backwards();
+ buffer_print();
+ break;
+#endif
+#ifdef CONFIG_FEATURE_LESS_FLAGCS
+ case '-':
+ flag_change();
+ buffer_print();
+ break;
+ case '_':
+ show_flag_status();
+ break;
+#endif
+#ifdef CONFIG_FEATURE_LESS_BRACKETS
+ case '{': case '(': case '[':
+ match_right_bracket(keypress);
+ break;
+ case '}': case ')': case ']':
+ match_left_bracket(keypress);
+ break;
+#endif
+ case ':':
+ colon_process();
+ break;
+ default:
+ break;
+ }
+ if (isdigit(keypress))
+ number_process(keypress);
+}
int less_main(int argc, char **argv) {
-
+
unsigned long flags;
int keypress;
-
+
flags = bb_getopt_ulflags(argc, argv, "EMNm~");
E_FLAG = (flags & 1);
M_FLAG = (flags & 2);
argv += optind;
files = argv;
num_files = argc;
-
+
if (!num_files) {
if (ttyname(STDIN_FILENO) == NULL)
inp_stdin = 1;
bb_show_usage();
}
}
-
+
strcpy(filename, (inp_stdin) ? "stdin" : files[0]);
tty_width_height();
data_readlines();
buffer_init();
buffer_print();
-
+
while (1) {
keypress = tless_getch();
keypress_process(keypress);