diff options
author | Denis Vlasenko | 2008-10-24 22:43:27 +0000 |
---|---|---|
committer | Denis Vlasenko | 2008-10-24 22:43:27 +0000 |
commit | 53c80f09723fa5e9bccd6fbab9c11b14ed520404 (patch) | |
tree | 1c05b9eb8166124b0ac9fb74587aca6459634755 /miscutils/less.c | |
parent | aa2a1c000c360d89c36c9b1138473ab5f57a946f (diff) | |
download | busybox-53c80f09723fa5e9bccd6fbab9c11b14ed520404.zip busybox-53c80f09723fa5e9bccd6fbab9c11b14ed520404.tar.gz |
less: add optional line number toggle and resizing on SIGWINCH.
Diffstat (limited to 'miscutils/less.c')
-rw-r--r-- | miscutils/less.c | 151 |
1 files changed, 89 insertions, 62 deletions
diff --git a/miscutils/less.c b/miscutils/less.c index 1af9685..f367b0e 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -28,13 +28,6 @@ #include "xregex.h" #endif -/* In progress */ -#define ENABLE_FEATURE_LESS_REWRAP 0 - -/* FIXME: currently doesn't work right */ -#undef ENABLE_FEATURE_LESS_FLAGCS -#define ENABLE_FEATURE_LESS_FLAGCS 0 - /* The escape codes for highlighted and normal text */ #define HIGHLIGHT "\033[7m" #define NORMAL "\033[0m" @@ -77,14 +70,14 @@ enum { /* Command line options */ enum { - FLAG_E = 1, + FLAG_E = 1 << 0, FLAG_M = 1 << 1, FLAG_m = 1 << 2, FLAG_N = 1 << 3, FLAG_TILDE = 1 << 4, FLAG_I = 1 << 5, + FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_DASHCMD, /* hijack command line options variable for internal state vars */ - LESS_STATE_NO_WRAP = 1 << 14, LESS_STATE_MATCH_BACKWARDS = 1 << 15, }; @@ -98,10 +91,13 @@ struct globals { int less_gets_pos; /* last position in last line, taking into account tabs */ size_t linepos; - unsigned max_displayed_line; unsigned max_fline; unsigned max_lineno; /* this one tracks linewrap */ + unsigned max_displayed_line; unsigned width; +#if ENABLE_FEATURE_LESS_WINCH + unsigned winch_counter; +#endif ssize_t eof_error; /* eof if 0, error if < 0 */ ssize_t readpos; ssize_t readeof; /* must be signed */ @@ -132,10 +128,11 @@ struct globals { #define kbd_fd (G.kbd_fd ) #define less_gets_pos (G.less_gets_pos ) #define linepos (G.linepos ) -#define max_displayed_line (G.max_displayed_line) #define max_fline (G.max_fline ) #define max_lineno (G.max_lineno ) +#define max_displayed_line (G.max_displayed_line) #define width (G.width ) +#define winch_counter (G.winch_counter ) #define eof_error (G.eof_error ) #define readpos (G.readpos ) #define readeof (G.readeof ) @@ -218,7 +215,7 @@ static void less_exit(int code) exit(code); } -#if ENABLE_FEATURE_LESS_REWRAP +#if ENABLE_FEATURE_LESS_LINENUMS || ENABLE_FEATURE_LESS_WINCH static void re_wrap(void) { int w = width; @@ -297,6 +294,7 @@ static void re_wrap(void) linepos = 0; // XXX cur_fline = new_cur_fline; /* max_lineno is screen-size independent */ + pattern_valid = 0; } #endif @@ -426,7 +424,11 @@ static void read_lines(void) eof_error = 0; /* Pretend we saw EOF */ break; } - if (max_fline > cur_fline + max_displayed_line) { + if (!(option_mask32 & FLAG_S) + ? (max_fline > cur_fline + max_displayed_line) + : (max_fline >= cur_fline + && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line) + ) { #if !ENABLE_FEATURE_LESS_REGEXP break; #else @@ -719,18 +721,19 @@ static void buffer_print(void) status_print(); } -#if ENABLE_FEATURE_LESS_REWRAP static void buffer_fill_and_print(void) { - unsigned i = 0; - int fpos = cur_fline + i; + unsigned i; +#if ENABLE_FEATURE_LESS_DASHCMD + int fpos = cur_fline; - if (option_mask32 & LESS_STATE_NO_WRAP) { + if (option_mask32 & FLAG_S) { /* Go back to the beginning of this line */ while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1])) fpos--; } + i = 0; while (i <= max_displayed_line && fpos <= max_fline) { int lineno = LINENO(flines[fpos]); buffer[i] = flines[fpos]; @@ -738,28 +741,20 @@ static void buffer_fill_and_print(void) do { fpos++; } while ((fpos <= max_fline) - && (option_mask32 & LESS_STATE_NO_WRAP) + && (option_mask32 & FLAG_S) && lineno == LINENO(flines[fpos]) ); } - for (; i <= max_displayed_line; i++) { - buffer[i] = empty_line_marker; - } - buffer_print(); -} #else -static void buffer_fill_and_print(void) -{ - unsigned i; for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) { buffer[i] = flines[cur_fline + i]; } +#endif for (; i <= max_displayed_line; i++) { buffer[i] = empty_line_marker; } buffer_print(); } -#endif /* Move the buffer up and down in the file in order to scroll */ static void buffer_down(int nlines) @@ -857,7 +852,19 @@ static ssize_t getch_nowait(char* input, int sz) if (less_gets_pos >= 0) move_cursor(max_displayed_line + 2, less_gets_pos + 1); fflush(stdout); +#if ENABLE_FEATURE_LESS_WINCH + while (1) { + int r; + r = poll(pfd + rd, 2 - rd, -1); + if (/*r < 0 && errno == EINTR &&*/ winch_counter) { + input[0] = '\\'; /* anything which has no defined function */ + return 1; + } + if (r) break; + } +#else safe_poll(pfd + rd, 2 - rd, -1); +#endif input[0] = '\0'; rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */ @@ -1114,7 +1121,7 @@ static void regex_process(void) /* Compile the regex and check for errors */ err = regcomp_or_errmsg(&pattern, uncomp_regex, - option_mask32 & FLAG_I ? REG_ICASE : 0); + (option_mask32 & FLAG_I) ? REG_ICASE : 0); free(uncomp_regex); if (err) { print_statusline(err); @@ -1208,7 +1215,7 @@ static void number_process(int first_digit) } } -#if ENABLE_FEATURE_LESS_FLAGCS +#if ENABLE_FEATURE_LESS_DASHCMD static void flag_change(void) { int keypress; @@ -1230,6 +1237,17 @@ static void flag_change(void) case '~': option_mask32 ^= FLAG_TILDE; break; + case 'S': + option_mask32 ^= FLAG_S; + buffer_fill_and_print(); + break; +#if ENABLE_FEATURE_LESS_LINENUMS + case 'N': + option_mask32 ^= FLAG_N; + re_wrap(); + buffer_fill_and_print(); + break; +#endif } } @@ -1467,7 +1485,7 @@ static void keypress_process(int keypress) regex_process(); break; #endif -#if ENABLE_FEATURE_LESS_FLAGCS +#if ENABLE_FEATURE_LESS_DASHCMD case '-': flag_change(); buffer_print(); @@ -1487,25 +1505,6 @@ static void keypress_process(int keypress) case ':': colon_process(); break; -#if ENABLE_FEATURE_LESS_REWRAP - case '*': /* Should be -N command / option */ - option_mask32 ^= FLAG_N; - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); - if (width < 20) /* 20: two tabstops + 4 */ - width = 20; - if (max_displayed_line < 3) - max_displayed_line = 3; - max_displayed_line -= 2; - free(buffer); - buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); - re_wrap(); - buffer_fill_and_print(); - break; - case '&': /* Should be -S command / option */ - option_mask32 ^= LESS_STATE_NO_WRAP; - buffer_fill_and_print(); - break; -#endif } if (isdigit(keypress)) @@ -1517,6 +1516,13 @@ static void sig_catcher(int sig) less_exit(- sig); } +#if ENABLE_FEATURE_LESS_WINCH +static void sigwinch_handler(int sig UNUSED_PARAM) +{ + winch_counter++; +} +#endif + int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int less_main(int argc, char **argv) { @@ -1527,7 +1533,7 @@ int less_main(int argc, char **argv) /* TODO: -x: do not interpret backspace, -xx: tab also */ /* -xxx: newline also */ /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */ - getopt32(argv, "EMmN~I"); + getopt32(argv, "EMmN~I" USE_FEATURE_LESS_DASHCMD("S")); argc -= optind; argv += optind; num_files = argc; @@ -1537,10 +1543,6 @@ int less_main(int argc, char **argv) * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); - kbd_fd = open(CURRENT_TTY, O_RDONLY); - if (kbd_fd < 0) - return bb_cat(argv); - ndelay_on(kbd_fd); if (!num_files) { if (isatty(STDIN_FILENO)) { @@ -1548,19 +1550,18 @@ int less_main(int argc, char **argv) bb_error_msg("missing filename"); bb_show_usage(); } - } else + } else { filename = xstrdup(files[0]); + } - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); - /* 20: two tabstops + 4 */ - if (width < 20 || max_displayed_line < 3) - return bb_cat(argv); - max_displayed_line -= 2; - - buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); if (option_mask32 & FLAG_TILDE) empty_line_marker = ""; + kbd_fd = open(CURRENT_TTY, O_RDONLY); + if (kbd_fd < 0) + return bb_cat(argv); + ndelay_on(kbd_fd); + tcgetattr(kbd_fd, &term_orig); term_less = term_orig; term_less.c_lflag &= ~(ICANON | ECHO); @@ -1569,11 +1570,37 @@ int less_main(int argc, char **argv) term_less.c_cc[VMIN] = 1; term_less.c_cc[VTIME] = 0; + get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + /* 20: two tabstops + 4 */ + if (width < 20 || max_displayed_line < 3) + return bb_cat(argv); + max_displayed_line -= 2; + /* We want to restore term_orig on exit */ bb_signals(BB_FATAL_SIGS, sig_catcher); +#if ENABLE_FEATURE_LESS_WINCH + signal(SIGWINCH, sigwinch_handler); +#endif + buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); reinitialize(); while (1) { +#if ENABLE_FEATURE_LESS_WINCH + if (winch_counter) { + winch_counter--; + get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + /* 20: two tabstops + 4 */ + if (width < 20) + width = 20; + if (max_displayed_line < 3) + max_displayed_line = 3; + max_displayed_line -= 2; + free(buffer); + buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); + re_wrap(); + buffer_fill_and_print(); + } +#endif keypress = less_getch(-1); /* -1: do not position cursor */ keypress_process(keypress); } |