more correction for getopt_ulflags() documentation by author of this fuck logic
[oweals/busybox.git] / miscutils / less.c
index d7898caab96ee5df2e5555cce18cbe2a7d693e82..189b886f712c5480e35516db3d4f0014c16936e4 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  * 02111-1307 USA
  *
- *     This program needs a lot of development, so consider it in a beta stage
- *     at best.
+ *      This program needs a lot of development, so consider it in a beta stage
+ *      at best.
  *
- *     TODO:
- *     - Add more regular expression support - search modifiers, certain matches, etc.
- *     - Add more complex bracket searching - currently, nested brackets are
- *     not considered.
- *     - Add support for "F" as an input. This causes less to act in
- *     a similar way to tail -f.
- *     - Check for binary files, and prompt the user if a binary file
- *     is detected.
- *     - Allow horizontal scrolling. Currently, lines simply continue onto
- *     the next line, per the terminal's discretion
+ *      TODO:
+ *      - Add more regular expression support - search modifiers, certain matches, etc.
+ *      - Add more complex bracket searching - currently, nested brackets are
+ *      not considered.
+ *      - Add support for "F" as an input. This causes less to act in
+ *      a similar way to tail -f.
+ *      - Check for binary files, and prompt the user if a binary file
+ *      is detected.
+ *      - Allow horizontal scrolling. Currently, lines simply continue onto
+ *      the next line, per the terminal's discretion
  *
- *     Notes:
- *     - filename is an array and not a pointer because that avoids all sorts
- *     of complications involving the fact that something that is pointed to
- *     will be changed if the pointer is changed.
- *     - the inp file pointer is used so that keyboard input works after
- *     redirected input has been read from stdin
+ *      Notes:
+ *      - filename is an array and not a pointer because that avoids all sorts
+ *      of complications involving the fact that something that is pointed to
+ *      will be changed if the pointer is changed.
+ *      - the inp file pointer is used so that keyboard input works after
+ *      redirected input has been read from stdin
 */
 
 #include <stdio.h>
@@ -77,7 +77,7 @@
 #define NORMAL "\033[0m"
 
 /* The escape code to clear the screen */
-#define CLEAR "\033[2J"
+#define CLEAR "\033[H\033[J"
 
 /* Maximum number of lines in a file */
 #define MAXLINES 10000
@@ -89,8 +89,8 @@ static int height;
 static int width;
 static char **files;
 static char filename[256];
-static char buffer[100][256];
-static char *flines[MAXLINES];
+static char **buffer;
+static char **flines;
 static int current_file = 1;
 static int line_pos;
 static int num_flines;
@@ -98,20 +98,16 @@ static int num_files = 1;
 static int past_eof;
 
 /* Command line options */
-static int E_FLAG;
-static int M_FLAG;
-static int N_FLAG;
-static int m_FLAG;
-static int TILDE_FLAG;
+static unsigned long flags;
+#define FLAG_E 1
+#define FLAG_M (1<<1)
+#define FLAG_m (1<<2)
+#define FLAG_N (1<<3)
+#define FLAG_TILDE (1<<4)
 
 /* This is needed so that program behaviour changes when input comes from
    stdin */
 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
-   the keyboard still stays the same. If it switched back to stdin, keyboard
-   input wouldn't work. */
-static int ea_inp_stdin;
 
 #ifdef CONFIG_FEATURE_LESS_MARKS
 static int mark_lines[15][2];
@@ -136,19 +132,12 @@ static FILE *inp;
 /* Reset terminal input to normal */
 static void set_tty_cooked(void) {
        fflush(stdout);
-       tcsetattr(0, TCSANOW, &term_orig);
+       tcsetattr(fileno(inp), TCSANOW, &term_orig);
 }
 
-/* Set terminal input to raw mode */
+/* Set terminal input to raw mode  (taken from vi.c) */
 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);
+       tcsetattr(fileno(inp), TCSANOW, &term_vi);
 }
 
 /* Exit the program gracefully */
@@ -168,36 +157,34 @@ static void tless_exit(int code) {
    special return codes. Note that this function works best with raw input. */
 static int tless_getch(void) {
 
+       int input;
+
        set_tty_raw();
-       char input_key[3];
 
-       input_key[0] = getc(inp);
+       input = 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);
+       if (input == '\033' && getc(inp) == '[') {
+               input = getc(inp);
                set_tty_cooked();
-               if (input_key[1] == '[') {
-                       if (input_key[2] == REAL_KEY_UP)
-                               return KEY_UP;
-                       else if (input_key[2] == REAL_KEY_DOWN)
-                               return KEY_DOWN;
-                       else if (input_key[2] == REAL_KEY_RIGHT)
-                               return KEY_RIGHT;
-                       else if (input_key[2] == REAL_KEY_LEFT)
-                               return KEY_LEFT;
-                       else if (input_key[2] == REAL_PAGE_UP)
-                               return PAGE_UP;
-                       else if (input_key[2] == REAL_PAGE_DOWN)
-                               return PAGE_DOWN;
-               }
+               if (input == REAL_KEY_UP)
+                       return KEY_UP;
+               else if (input == REAL_KEY_DOWN)
+                       return KEY_DOWN;
+               else if (input == REAL_KEY_RIGHT)
+                       return KEY_RIGHT;
+               else if (input == REAL_KEY_LEFT)
+                       return KEY_LEFT;
+               else if (input == REAL_PAGE_UP)
+                       return PAGE_UP;
+               else if (input == REAL_PAGE_DOWN)
+                       return PAGE_DOWN;
        }
        /* The input is a normal ASCII value */
        else {
                set_tty_cooked();
-               return input_key[0];
+               return input;
        }
        return 0;
 }
@@ -221,8 +208,7 @@ static void add_linenumbers(void) {
 
        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);
+               flines[i] = bb_xasprintf("%5d %s", i + 1, current_line);
        }
 }
 
@@ -233,52 +219,31 @@ static void data_readlines(void) {
        FILE *fp;
 
        fp = (inp_stdin) ? stdin : bb_xfopen(filename, "rt");
-
-       for (i = 0; (!feof(fp)) && (i <= MAXLINES); i++) {
+       flines = NULL;
+       for (i = 0; (feof(fp)==0) && (i <= MAXLINES); i++) {
                strcpy(current_line, "");
                fgets(current_line, 256, fp);
-               bb_xferror(fp, filename);
-               flines[i] = (char *) bb_xstrndup(current_line, (strlen(current_line) + 1) * sizeof(char));
+               if(fp != stdin)
+                       bb_xferror(fp, filename);
+               flines = xrealloc(flines, (i+1) * sizeof(char *));
+               flines[i] = bb_xstrdup(current_line);
        }
        num_flines = i - 2;
 
-/* Reset variables for a new file */
+       /* Reset variables for a new file */
 
        line_pos = 0;
        past_eof = 0;
 
        fclose(fp);
 
-       if (inp_stdin)
-               inp = fopen(CURRENT_TTY, "r");
-       else
-               inp = stdin;
-
-       if (ea_inp_stdin) {
-               fclose(inp);
-               inp = fopen(CURRENT_TTY, "r");
-       }
+       if(inp == NULL)
+               inp = (inp_stdin) ? fopen(CURRENT_TTY, "r") : stdin;
 
-       if (N_FLAG)
+       if (flags & FLAG_N)
                add_linenumbers();
 }
 
-/* Free the file data */
-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 */
-static int calc_percent(void) {
-       return ((100 * (line_pos + height - 2) / num_flines) + 1);
-}
-#endif
-
 /* Turn a percentage into a line number */
 static int reverse_percent(int percentage) {
        double linenum = percentage;
@@ -287,6 +252,13 @@ static int reverse_percent(int percentage) {
 }
 
 #ifdef CONFIG_FEATURE_LESS_FLAGS
+
+/* Interestingly, writing calc_percent as a function and not a prototype saves around 32 bytes
+ * on my build. */
+static int calc_percent(void) {
+       return ((100 * (line_pos + height - 2) / num_flines) + 1);
+}
+
 /* Print a status line if -M was specified */
 static void m_status_print(void) {
 
@@ -311,7 +283,7 @@ static void m_status_print(void) {
                }
                else {
                        percentage = calc_percent();
-                       printf("%i%s %s", percentage, "%", NORMAL);
+                       printf("%i%% %s", percentage, NORMAL);
                }
        }
        else {
@@ -329,11 +301,11 @@ static void medium_status_print(void) {
        percentage = calc_percent();
 
        if (!line_pos)
-               printf("%s%s %i%s%s", HIGHLIGHT, filename, percentage, "%", NORMAL);
+               printf("%s%s %i%%%s", HIGHLIGHT, filename, percentage, NORMAL);
        else if (line_pos == num_flines - height + 2)
                printf("%s(END)%s", HIGHLIGHT, NORMAL);
        else
-               printf("%s%i%s%s", HIGHLIGHT, percentage, "%", NORMAL);
+               printf("%s%i%%%s", HIGHLIGHT, percentage, NORMAL);
 }
 #endif
 
@@ -342,9 +314,9 @@ static void status_print(void) {
 
        /* Change the status if flags have been set */
 #ifdef CONFIG_FEATURE_LESS_FLAGS
-       if (M_FLAG)
+       if (flags & FLAG_M)
                m_status_print();
-       else if (m_FLAG)
+       else if (flags & FLAG_m)
                medium_status_print();
        /* No flags set */
        else {
@@ -360,7 +332,7 @@ static void status_print(void) {
                                printf("%s%s%s%s", HIGHLIGHT, "- Next: ", files[current_file], NORMAL);
                }
                else {
-                       printf("%c", ':');
+                       putchar(':');
                }
 #ifdef CONFIG_FEATURE_LESS_FLAGS
        }
@@ -372,22 +344,19 @@ static void buffer_print(void) {
 
        int i;
 
+       printf("%s", CLEAR);
        if (num_flines >= height - 2) {
-               printf("%s", CLEAR);
-               move_cursor(0,0);
                for (i = 0; i < height - 1; i++)
                        printf("%s", buffer[i]);
-               status_print();
        }
        else {
-               printf("%s", CLEAR);
-               move_cursor(0,0);
                for (i = 1; i < (height - 1 - num_flines); i++)
                        putchar('\n');
                for (i = 0; i < height - 1; i++)
                        printf("%s", buffer[i]);
-               status_print();
        }
+
+       status_print();
 }
 
 /* Initialise the buffer */
@@ -395,18 +364,23 @@ static void buffer_init(void) {
 
        int i;
 
-       for (i = 0; i < (height - 1); i++)
-               memset(buffer[i], '\0', 256);
+       if(buffer == NULL) {
+               /* malloc the number of lines needed for the buffer */
+               buffer = xrealloc(buffer, height * sizeof(char *));
+       } else {
+               for (i = 0; i < (height - 1); i++)
+                       free(buffer[i]);
+       }
 
        /* 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]);
+               buffer[i] = bb_xstrdup(flines[i]);
        }
 
        /* If the buffer still isn't full, fill it with blank lines */
        for (; i < (height - 1); i++) {
-               strcpy(buffer[i], "");
+               buffer[i] = bb_xstrdup("");
        }
 }
 
@@ -418,21 +392,25 @@ static void buffer_down(int nlines) {
        if (!past_eof) {
                if (line_pos + (height - 3) + nlines < num_flines) {
                        line_pos += nlines;
-                       for (i = 0; i < (height - 1); i++)
-                               strcpy(buffer[i], flines[line_pos + i]);
+                       for (i = 0; i < (height - 1); i++) {
+                               free(buffer[i]);
+                               buffer[i] = bb_xstrdup(flines[line_pos + i]);
+                       }
                }
                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) {
                                line_pos += 1;
-                               for (i = 0; i < (height - 1); i++)
-                                       strcpy(buffer[i], flines[line_pos + i]);
+                               for (i = 0; i < (height - 1); i++) {
+                                       free(buffer[i]);
+                                       buffer[i] = bb_xstrdup(flines[line_pos + i]);
+                               }
                        }
                }
 
                /* We exit if the -E flag has been set */
-               if (E_FLAG && (line_pos + (height - 2) == num_flines))
+               if ((flags & FLAG_E) && (line_pos + (height - 2) == num_flines))
                        tless_exit(0);
        }
 }
@@ -445,16 +423,20 @@ static void buffer_up(int nlines) {
        if (!past_eof) {
                if (line_pos - nlines >= 0) {
                        line_pos -= nlines;
-                       for (i = 0; i < (height - 1); i++)
-                               strcpy(buffer[i], flines[line_pos + i]);
+                       for (i = 0; i < (height - 1); i++) {
+                               free(buffer[i]);
+                               buffer[i] = bb_xstrdup(flines[line_pos + i]);
+                       }
                }
                else {
                /* As the requested number of lines to move was too large, we
                   move one line up at a time until we can't. */
                        while (line_pos != 0) {
                                line_pos -= 1;
-                               for (i = 0; i < (height - 1); i++)
-                                       strcpy(buffer[i], flines[line_pos + i]);
+                               for (i = 0; i < (height - 1); i++) {
+                                       free(buffer[i]);
+                                       buffer[i] = bb_xstrdup(flines[line_pos + i]);
+                               }
                        }
                }
        }
@@ -473,11 +455,12 @@ static void buffer_up(int nlines) {
                        /* We only move part of the buffer, as the rest
                        is past the EOF */
                        for (i = 0; i < (height - 1); i++) {
+                               free(buffer[i]);
                                if (i < tilde_line - nlines + 1)
-                                       strcpy(buffer[i], flines[line_pos + i]);
+                                       buffer[i] = bb_xstrdup(flines[line_pos + i]);
                                else {
                                        if (line_pos >= num_flines - height + 2)
-                                               strcpy(buffer[i], "~\n");
+                                               buffer[i] = bb_xstrdup("~\n");
                                }
                        }
                }
@@ -495,16 +478,19 @@ static void buffer_line(int linenum) {
                printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum, NORMAL);
        }
        else if (linenum < (num_flines - height - 2)) {
-               for (i = 0; i < (height - 1); i++)
-                       strcpy(buffer[i], flines[linenum + i]);
+               for (i = 0; i < (height - 1); i++) {
+                       free(buffer[i]);
+                       buffer[i] = bb_xstrdup(flines[linenum + i]);
+               }
                line_pos = linenum;
        }
        else {
                for (i = 0; i < (height - 1); i++) {
+                       free(buffer[i]);
                        if (linenum + i < num_flines + 2)
-                               strcpy(buffer[i], flines[linenum + i]);
+                               buffer[i] = bb_xstrdup(flines[linenum + i]);
                        else
-                               strcpy(buffer[i], (TILDE_FLAG) ? "\n" : "~\n");
+                               buffer[i] = bb_xstrdup((flags & FLAG_TILDE) ? "\n" : "~\n");
                }
                line_pos = linenum;
                /* Set past_eof so buffer_down and buffer_up act differently */
@@ -512,6 +498,20 @@ static void buffer_line(int linenum) {
        }
 }
 
+/* Reinitialise everything for a new file - free the memory and start over */
+static void reinitialise(void) {
+
+       int i;
+
+       for (i = 0; i <= num_flines; i++)
+               free(flines[i]);
+       free(flines);
+
+       data_readlines();
+       buffer_init();
+       buffer_print();
+}
+
 static void examine_file(void) {
 
        int newline_offset;
@@ -525,58 +525,28 @@ static void examine_file(void) {
        newline_offset = strlen(filename) - 1;
        filename[newline_offset] = '\0';
 
-       files[num_files] = bb_xstrndup(filename, (strlen(filename) + 1) * sizeof(char));
+       files[num_files] = bb_xstrdup(filename);
        current_file = num_files + 1;
        num_files++;
 
        inp_stdin = 0;
-       ea_inp_stdin = 1;
-       free_flines();
-       data_readlines();
-       buffer_init();
-       buffer_print();
+       reinitialise();
 }
 
-
-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--;
+/* This function changes the file currently being paged. direction can be one of the following:
+ * -1: go back one file
+ *  0: go to the first file
+ *  1: go forward one file
+*/
+static void change_file (int direction) {
+       if (current_file != ((direction > 0) ? num_files : 1)) {
+               current_file = direction ? current_file + direction : 1;
                strcpy(filename, files[current_file - 1]);
-
-               free_flines();
-               data_readlines();
-               buffer_init();
-               buffer_print();
+               reinitialise();
        }
        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();
+               printf("%s%s%s", HIGHLIGHT, (direction > 0) ? "No next file" : "No previous file", NORMAL);
        }
 }
 
@@ -585,14 +555,14 @@ static void remove_current_file(void) {
        int i;
 
        if (current_file != 1) {
-               previous_file();
+               change_file(-1);
                for (i = 3; i <= num_files; i++)
                        files[i - 2] = files[i - 1];
                num_files--;
                buffer_print();
        }
        else {
-               next_file();
+               change_file(1);
                for (i = 2; i <= num_files; i++)
                        files[i - 2] = files[i - 1];
                num_files--;
@@ -624,16 +594,16 @@ static void colon_process(void) {
                        break;
 #endif
                case 'n':
-                       next_file();
+                       change_file(1);
                        break;
                case 'p':
-                       previous_file();
+                       change_file(-1);
                        break;
                case 'q':
                        tless_exit(0);
                        break;
                case 'x':
-                       first_file();
+                       change_file(0);
                        break;
                default:
                        break;
@@ -648,16 +618,8 @@ static void colon_process(void) {
 
 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;
+       return bb_xasprintf("%.*s%s%.*s%s%s", start, line, HIGHLIGHT,
+                       end - start, line + start, NORMAL, line + end);
 }
 
 static char *process_regex_on_line(char *line, regex_t *pattern) {
@@ -671,7 +633,7 @@ static char *process_regex_on_line(char *line, regex_t *pattern) {
        char sub_line[256];
        int prev_eo = 0;
        regmatch_t match_structs;
-       
+
        memset(sub_line, 0, 256);
        strcpy(line2, line);
 
@@ -715,11 +677,16 @@ static void regex_process(void) {
 
        /* Get the uncompiled regular expression from the user */
        clear_line();
-       if (match_backwards)
-               printf("?");
-       else
-               printf("/");
-       scanf("%s", uncomp_regex);
+       putchar((match_backwards) ? '?' : '/');
+       uncomp_regex[0] = 0;
+       fgets(uncomp_regex, sizeof(uncomp_regex), stdin);
+       i = strlen(uncomp_regex);
+       if(i > 0) {
+               if(uncomp_regex[i-1] == '\n')
+                       uncomp_regex[i-1] = '\0';
+               else
+                       while((i = getchar()) != '\n' && i != EOF);
+       }
 
        /* Compile the regex and check for errors */
        xregcomp(pattern, uncomp_regex, 0);
@@ -727,8 +694,7 @@ static void regex_process(void) {
        /* 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));
-
+               flines[i] = bb_xstrdup(current_line);
                if (match_found) {
                        match_lines[j] = i;
                        j++;
@@ -736,7 +702,6 @@ static void regex_process(void) {
        }
 
        num_matches = j;
-
        if ((match_lines[0] != -1) && (num_flines > height - 2))
                buffer_line(match_lines[0]);
        else
@@ -781,62 +746,60 @@ static void number_process(int first_digit) {
        int num;
        char num_input[80];
        char keypress;
+       char *endptr;
+
        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]);
+       /* Receive input until a letter is given (max 80 chars)*/
+       while((i < 80) && (num_input[i] = tless_getch()) && isdigit(num_input[i])) {
+               putchar(num_input[i]);
                i++;
        }
 
        /* Take the final letter out of the digits string */
        keypress = num_input[i];
        num_input[i] = '\0';
-       i--;
-       num = atoi(num_input);
+       num = strtol(num_input, &endptr, 10);
+       if (endptr==num_input || *endptr!='\0' || num < 1 || num > MAXLINES)
+               goto END;
 
        /* We now know the number and the letter entered, so we process them */
        switch (keypress) {
                case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
                        buffer_down(num);
-                       buffer_print();
                        break;
                case KEY_UP: case 'b': case 'w': case 'y': case 'u':
                        buffer_up(num);
-                       buffer_print();
                        break;
                case 'g': case '<': case 'G': case '>':
                        if (num_flines >= height - 2)
                                buffer_line(num - 1);
-                       buffer_print();
                        break;
                case 'p': case '%':
                        buffer_line(reverse_percent(num));
-                       buffer_print();
                        break;
 #ifdef CONFIG_FEATURE_LESS_REGEXP
                case 'n':
                        goto_match(match_pos + num - 1);
-                       buffer_print();
                        break;
                case '/':
                        regex_process();
                        goto_match(num - 1);
-                       buffer_print();
                        break;
                case '?':
                        num_back_match = num;
                        search_backwards();
-                       buffer_print();
                        break;
 #endif
                default:
                        break;
        }
+END:
+       buffer_print();
 }
 
 #ifdef CONFIG_FEATURE_LESS_FLAGCS
@@ -845,21 +808,21 @@ static void flag_change(void) {
        int keypress;
 
        clear_line();
-       printf("-");
+       putchar('-');
        keypress = tless_getch();
 
        switch (keypress) {
                case 'M':
-                       M_FLAG = !M_FLAG;
+                       flags ^= FLAG_M;
                        break;
                case 'm':
-                       m_FLAG = !m_FLAG;
+                       flags ^= FLAG_m;
                        break;
                case 'E':
-                       E_FLAG = !E_FLAG;
+                       flags ^= FLAG_E;
                        break;
                case '~':
-                       TILDE_FLAG = !TILDE_FLAG;
+                       flags ^= FLAG_TILDE;
                        break;
                default:
                        break;
@@ -872,24 +835,24 @@ static void show_flag_status(void) {
        int flag_val;
 
        clear_line();
-       printf("_");
+       putchar('_');
        keypress = tless_getch();
 
        switch (keypress) {
                case 'M':
-                       flag_val = M_FLAG;
+                       flag_val = flags & FLAG_M;
                        break;
                case 'm':
-                       flag_val = m_FLAG;
+                       flag_val = flags & FLAG_m;
                        break;
                case '~':
-                       flag_val = TILDE_FLAG;
+                       flag_val = flags & FLAG_TILDE;
                        break;
                case 'N':
-                       flag_val = N_FLAG;
+                       flag_val = flags & FLAG_N;
                        break;
                case 'E':
-                       flag_val = E_FLAG;
+                       flag_val = flags & FLAG_E;
                        break;
                default:
                        flag_val = 0;
@@ -967,21 +930,19 @@ static void goto_mark(void) {
        clear_line();
        printf("Go to mark: ");
        letter = tless_getch();
+       clear_line();
+
        if (isalpha(letter)) {
                for (i = 0; i <= num_marks; i++)
                        if (letter == mark_lines[i][0]) {
                                buffer_line(mark_lines[i][1]);
                                break;
                        }
-               if ((num_marks == 14) && (letter != mark_lines[14][0])) {
-                       clear_line();
+               if ((num_marks == 14) && (letter != mark_lines[14][0]))
                        printf("%s%s%s", HIGHLIGHT, "Mark not set", NORMAL);
-               }
        }
-       else {
-               clear_line();
+       else
                printf("%s%s%s", HIGHLIGHT, "Invalid mark letter", NORMAL);
-       }
 }
 #endif
 
@@ -1014,10 +975,10 @@ static void match_right_bracket(char bracket) {
        int bracket_line = -1;
        int i;
 
-       if (strchr(flines[line_pos], bracket) == NULL) {
-               clear_line();
+       clear_line();
+
+       if (strchr(flines[line_pos], bracket) == NULL)
                printf("%s%s%s", HIGHLIGHT, "No bracket in top line", NORMAL);
-       }
        else {
                for (i = line_pos + 1; i < num_flines; i++) {
                        if (strchr(flines[i], opp_bracket(bracket)) != NULL) {
@@ -1026,10 +987,8 @@ static void match_right_bracket(char bracket) {
                        }
                }
 
-               if (bracket_line == -1) {
-                       clear_line();
+               if (bracket_line == -1)
                        printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
-               }
 
                buffer_line(bracket_line - height + 2);
                buffer_print();
@@ -1041,8 +1000,9 @@ static void match_left_bracket (char bracket) {
        int bracket_line = -1;
        int i;
 
+       clear_line();
+
        if (strchr(flines[line_pos + height - 2], bracket) == NULL) {
-               clear_line();
                printf("%s%s%s", HIGHLIGHT, "No bracket in bottom line", NORMAL);
                printf("%s", flines[line_pos + height]);
                sleep(4);
@@ -1055,10 +1015,8 @@ static void match_left_bracket (char bracket) {
                        }
                }
 
-               if (bracket_line == -1) {
-                       clear_line();
+               if (bracket_line == -1)
                        printf("%s%s%s", HIGHLIGHT, "No matching bracket found", NORMAL);
-               }
 
                buffer_line(bracket_line);
                buffer_print();
@@ -1174,21 +1132,16 @@ static void keypress_process(int keypress) {
                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);
-       N_FLAG = (flags & 4);
-       m_FLAG = (flags & 8);
-       TILDE_FLAG = (flags & 16);
+       flags = bb_getopt_ulflags(argc, argv, "EMmN~");
 
        argc -= optind;
        argv += optind;
@@ -1204,9 +1157,16 @@ int less_main(int argc, char **argv) {
                }
        }
 
-       strcpy(filename, (inp_stdin) ? "stdin" : files[0]);
+       strcpy(filename, (inp_stdin) ? bb_msg_standard_input : files[0]);
        tty_width_height();
        data_readlines();
+       tcgetattr(fileno(inp), &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;
        buffer_init();
        buffer_print();