less: update line input so that it doesn't interfere with
screen update. Makes "man bash", [enter], [/], <enter search pattern>, [enter] more usable - manpage draws as you enter the pattern! Yay!! less: fix bug where backspace wasn't actually deleting chars less: "examine file with empty name" doesn't abort anymore. libbb: add "all fatal signals" mask. getch_nowait - 207 +207 status_print - 105 +105 examine_file 64 87 +23 move_cursor - 16 +16 m_status_print 185 195 +10 less_main 1656 1663 +7 decode_format_string 790 795 +5 test_main 403 405 +2 process0_stdin 247 249 +2 passwd_main 1070 1072 +2 less_gets 196 178 -18 buffer_print 169 71 -98 less_getch 362 138 -224 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 7/3 up/down: 379/-340) Total: 39 bytes text data bss dec hex filename 798329 740 7484 806553 c4e99 busybox_old 798368 740 7484 806592 c4ec0 busybox_unstripped
This commit is contained in:
parent
86620756d2
commit
33196372be
@ -274,9 +274,32 @@ char *xrealloc_getcwd_or_warn(char *cwd);
|
|||||||
|
|
||||||
char *xmalloc_follow_symlinks(const char *path);
|
char *xmalloc_follow_symlinks(const char *path);
|
||||||
|
|
||||||
//enum {
|
enum {
|
||||||
// BB_SIGS_FATAL = ,
|
/* bb_signals(BB_SIGS_FATAL, handler) catches all signals which
|
||||||
//};
|
* otherwise would kill us, except for those resulting from bugs:
|
||||||
|
* SIGSEGV, SIGILL, SIGFPE.
|
||||||
|
* Other fatal signals not included (TODO?):
|
||||||
|
* SIGBUS Bus error (bad memory access)
|
||||||
|
* SIGPOLL Pollable event. Synonym of SIGIO
|
||||||
|
* SIGPROF Profiling timer expired
|
||||||
|
* SIGSYS Bad argument to routine
|
||||||
|
* SIGTRAP Trace/breakpoint trap
|
||||||
|
*/
|
||||||
|
BB_SIGS_FATAL = 0
|
||||||
|
+ (1 << SIGHUP)
|
||||||
|
+ (1 << SIGINT)
|
||||||
|
+ (1 << SIGTERM)
|
||||||
|
+ (1 << SIGPIPE) // Write to pipe with no readers
|
||||||
|
+ (1 << SIGQUIT) // Quit from keyboard
|
||||||
|
+ (1 << SIGABRT) // Abort signal from abort(3)
|
||||||
|
+ (1 << SIGALRM) // Timer signal from alarm(2)
|
||||||
|
+ (1 << SIGVTALRM) // Virtual alarm clock
|
||||||
|
+ (1 << SIGXCPU) // CPU time limit exceeded
|
||||||
|
+ (1 << SIGXFSZ) // File size limit exceeded
|
||||||
|
+ (1 << SIGUSR1) // Yes kids, these are also fatal!
|
||||||
|
+ (1 << SIGUSR2)
|
||||||
|
+ 0,
|
||||||
|
};
|
||||||
void bb_signals(int sigs, void (*f)(int));
|
void bb_signals(int sigs, void (*f)(int));
|
||||||
/* Unlike signal() and bb_signals, sets handler with sigaction()
|
/* Unlike signal() and bb_signals, sets handler with sigaction()
|
||||||
* and in a way that while signal handler is run, no other signals
|
* and in a way that while signal handler is run, no other signals
|
||||||
|
@ -90,6 +90,7 @@ enum { pattern_valid = 0 };
|
|||||||
struct globals {
|
struct globals {
|
||||||
int cur_fline; /* signed */
|
int cur_fline; /* signed */
|
||||||
int kbd_fd; /* fd to get input from */
|
int kbd_fd; /* fd to get input from */
|
||||||
|
int less_gets_pos;
|
||||||
/* last position in last line, taking into account tabs */
|
/* last position in last line, taking into account tabs */
|
||||||
size_t linepos;
|
size_t linepos;
|
||||||
unsigned max_displayed_line;
|
unsigned max_displayed_line;
|
||||||
@ -123,6 +124,7 @@ struct globals {
|
|||||||
#define G (*ptr_to_globals)
|
#define G (*ptr_to_globals)
|
||||||
#define cur_fline (G.cur_fline )
|
#define cur_fline (G.cur_fline )
|
||||||
#define kbd_fd (G.kbd_fd )
|
#define kbd_fd (G.kbd_fd )
|
||||||
|
#define less_gets_pos (G.less_gets_pos )
|
||||||
#define linepos (G.linepos )
|
#define linepos (G.linepos )
|
||||||
#define max_displayed_line (G.max_displayed_line)
|
#define max_displayed_line (G.max_displayed_line)
|
||||||
#define max_fline (G.max_fline )
|
#define max_fline (G.max_fline )
|
||||||
@ -152,6 +154,7 @@ struct globals {
|
|||||||
#define term_less (G.term_less )
|
#define term_less (G.term_less )
|
||||||
#define INIT_G() do { \
|
#define INIT_G() do { \
|
||||||
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
|
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
|
||||||
|
less_gets_pos = -1; \
|
||||||
empty_line_marker = "~"; \
|
empty_line_marker = "~"; \
|
||||||
num_files = 1; \
|
num_files = 1; \
|
||||||
current_file = 1; \
|
current_file = 1; \
|
||||||
@ -385,6 +388,9 @@ static void m_status_print(void)
|
|||||||
{
|
{
|
||||||
int percentage;
|
int percentage;
|
||||||
|
|
||||||
|
if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
|
||||||
|
return;
|
||||||
|
|
||||||
clear_line();
|
clear_line();
|
||||||
printf(HIGHLIGHT"%s", filename);
|
printf(HIGHLIGHT"%s", filename);
|
||||||
if (num_files > 1)
|
if (num_files > 1)
|
||||||
@ -408,6 +414,9 @@ static void status_print(void)
|
|||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
|
if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
|
||||||
|
return;
|
||||||
|
|
||||||
/* Change the status if flags have been set */
|
/* Change the status if flags have been set */
|
||||||
#if ENABLE_FEATURE_LESS_FLAGS
|
#if ENABLE_FEATURE_LESS_FLAGS
|
||||||
if (option_mask32 & (FLAG_M|FLAG_m)) {
|
if (option_mask32 & (FLAG_M|FLAG_m)) {
|
||||||
@ -652,43 +661,46 @@ static void reinitialize(void)
|
|||||||
buffer_fill_and_print();
|
buffer_fill_and_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getch_nowait(char* input, int sz)
|
static ssize_t getch_nowait(char* input, int sz)
|
||||||
{
|
{
|
||||||
ssize_t rd;
|
ssize_t rd;
|
||||||
fd_set readfds;
|
struct pollfd pfd[2];
|
||||||
again:
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
/* NB: select returns whenever read will not block. Therefore:
|
pfd[0].fd = STDIN_FILENO;
|
||||||
* (a) with O_NONBLOCK'ed fds select will return immediately
|
pfd[0].events = POLLIN;
|
||||||
* (b) if eof is reached, select will also return
|
pfd[1].fd = kbd_fd;
|
||||||
* because read will immediately return 0 bytes.
|
pfd[1].events = POLLIN;
|
||||||
* Even if select says that input is available, read CAN block
|
again:
|
||||||
|
tcsetattr(kbd_fd, TCSANOW, &term_less);
|
||||||
|
/* NB: select/poll returns whenever read will not block. Therefore:
|
||||||
|
* if eof is reached, select/poll will return immediately
|
||||||
|
* because read will immediately return 0 bytes.
|
||||||
|
* Even if select/poll says that input is available, read CAN block
|
||||||
* (switch fd into O_NONBLOCK'ed mode to avoid it)
|
* (switch fd into O_NONBLOCK'ed mode to avoid it)
|
||||||
*/
|
*/
|
||||||
FD_ZERO(&readfds);
|
rd = 1;
|
||||||
if (max_fline <= cur_fline + max_displayed_line
|
if (max_fline <= cur_fline + max_displayed_line
|
||||||
&& eof_error > 0 /* did NOT reach eof yet */
|
&& eof_error > 0 /* did NOT reach eof yet */
|
||||||
) {
|
) {
|
||||||
/* We are interested in stdin */
|
/* We are interested in stdin */
|
||||||
FD_SET(0, &readfds);
|
rd = 0;
|
||||||
}
|
}
|
||||||
FD_SET(kbd_fd, &readfds);
|
/* position cursor if line input is done */
|
||||||
tcsetattr(kbd_fd, TCSANOW, &term_less);
|
if (less_gets_pos >= 0)
|
||||||
select(kbd_fd + 1, &readfds, NULL, NULL, NULL);
|
move_cursor(max_displayed_line + 2, less_gets_pos + 1);
|
||||||
|
fflush(stdout);
|
||||||
|
safe_poll(pfd + rd, 2 - rd, -1);
|
||||||
|
|
||||||
input[0] = '\0';
|
input[0] = '\0';
|
||||||
ndelay_on(kbd_fd);
|
rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */
|
||||||
rd = read(kbd_fd, input, sz);
|
if (rd < 0 && errno == EAGAIN) {
|
||||||
ndelay_off(kbd_fd);
|
/* No keyboard input -> we have input on stdin! */
|
||||||
if (rd < 0) {
|
|
||||||
/* No keyboard input, but we have input on stdin! */
|
|
||||||
if (errno != EAGAIN) /* Huh?? */
|
|
||||||
return;
|
|
||||||
read_lines();
|
read_lines();
|
||||||
buffer_fill_and_print();
|
buffer_fill_and_print();
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
set_tty_cooked();
|
||||||
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grab a character from input without requiring the return key. If the
|
/* Grab a character from input without requiring the return key. If the
|
||||||
@ -696,7 +708,7 @@ static void getch_nowait(char* input, int sz)
|
|||||||
* special return codes. Note that this function works best with raw input. */
|
* special return codes. Note that this function works best with raw input. */
|
||||||
static int less_getch(void)
|
static int less_getch(void)
|
||||||
{
|
{
|
||||||
char input[16];
|
unsigned char input[16];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
again:
|
again:
|
||||||
memset(input, 0, sizeof(input));
|
memset(input, 0, sizeof(input));
|
||||||
@ -705,7 +717,6 @@ static int less_getch(void)
|
|||||||
/* Detect escape sequences (i.e. arrow keys) and handle
|
/* Detect escape sequences (i.e. arrow keys) and handle
|
||||||
* them accordingly */
|
* them accordingly */
|
||||||
if (input[0] == '\033' && input[1] == '[') {
|
if (input[0] == '\033' && input[1] == '[') {
|
||||||
set_tty_cooked();
|
|
||||||
i = input[2] - REAL_KEY_UP;
|
i = input[2] - REAL_KEY_UP;
|
||||||
if (i < 4)
|
if (i < 4)
|
||||||
return 20 + i;
|
return 20 + i;
|
||||||
@ -724,8 +735,8 @@ static int less_getch(void)
|
|||||||
}
|
}
|
||||||
/* Reject almost all control chars */
|
/* Reject almost all control chars */
|
||||||
i = input[0];
|
i = input[0];
|
||||||
if (i < ' ' && i != 0x0d && i != 8) goto again;
|
if (i < ' ' && i != 0x0d && i != 8)
|
||||||
set_tty_cooked();
|
goto again;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,22 +745,21 @@ static char* less_gets(int sz)
|
|||||||
char c;
|
char c;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char *result = xzalloc(1);
|
char *result = xzalloc(1);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
/* I be damned if I know why is it needed *repeatedly*,
|
|
||||||
* but it is needed. Is it because of stdio? */
|
|
||||||
tcsetattr(kbd_fd, TCSANOW, &term_less);
|
|
||||||
|
|
||||||
c = '\0';
|
c = '\0';
|
||||||
read(kbd_fd, &c, 1);
|
less_gets_pos = sz + i;
|
||||||
if (c == 0x0d)
|
getch_nowait(&c, 1);
|
||||||
|
if (c == 0x0d) {
|
||||||
|
less_gets_pos = -1;
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
if (c == 0x7f)
|
if (c == 0x7f)
|
||||||
c = 8;
|
c = 8;
|
||||||
if (c == 8 && i) {
|
if (c == 8 && i) {
|
||||||
printf("\x8 \x8");
|
printf("\x8 \x8");
|
||||||
i--;
|
i--;
|
||||||
|
result[i] = '\0';
|
||||||
}
|
}
|
||||||
if (c < ' ')
|
if (c < ' ')
|
||||||
continue;
|
continue;
|
||||||
@ -764,9 +774,17 @@ static char* less_gets(int sz)
|
|||||||
|
|
||||||
static void examine_file(void)
|
static void examine_file(void)
|
||||||
{
|
{
|
||||||
|
char *new_fname;
|
||||||
|
|
||||||
print_statusline("Examine: ");
|
print_statusline("Examine: ");
|
||||||
|
new_fname = less_gets(sizeof("Examine: ")-1);
|
||||||
|
if (!new_fname[0]) {
|
||||||
|
free(new_fname);
|
||||||
|
status_print();
|
||||||
|
return;
|
||||||
|
}
|
||||||
free(filename);
|
free(filename);
|
||||||
filename = less_gets(sizeof("Examine: ")-1);
|
filename = new_fname;
|
||||||
/* files start by = argv. why we assume that argv is infinitely long??
|
/* files start by = argv. why we assume that argv is infinitely long??
|
||||||
files[num_files] = filename;
|
files[num_files] = filename;
|
||||||
current_file = num_files + 1;
|
current_file = num_files + 1;
|
||||||
@ -1087,7 +1105,7 @@ static void save_input_to_file(void)
|
|||||||
|
|
||||||
print_statusline("Log file: ");
|
print_statusline("Log file: ");
|
||||||
current_line = less_gets(sizeof("Log file: ")-1);
|
current_line = less_gets(sizeof("Log file: ")-1);
|
||||||
if (strlen(current_line) > 0) {
|
if (current_line[0]) {
|
||||||
fp = fopen(current_line, "w");
|
fp = fopen(current_line, "w");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
msg = "Error opening log file";
|
msg = "Error opening log file";
|
||||||
@ -1334,6 +1352,7 @@ int less_main(int argc, char **argv)
|
|||||||
kbd_fd = open(CURRENT_TTY, O_RDONLY);
|
kbd_fd = open(CURRENT_TTY, O_RDONLY);
|
||||||
if (kbd_fd < 0)
|
if (kbd_fd < 0)
|
||||||
return bb_cat(argv);
|
return bb_cat(argv);
|
||||||
|
ndelay_on(kbd_fd);
|
||||||
|
|
||||||
if (!num_files) {
|
if (!num_files) {
|
||||||
if (isatty(STDIN_FILENO)) {
|
if (isatty(STDIN_FILENO)) {
|
||||||
@ -1354,11 +1373,9 @@ int less_main(int argc, char **argv)
|
|||||||
if (option_mask32 & FLAG_TILDE)
|
if (option_mask32 & FLAG_TILDE)
|
||||||
empty_line_marker = "";
|
empty_line_marker = "";
|
||||||
|
|
||||||
|
bb_signals(BB_SIGS_FATAL, sig_catcher);
|
||||||
|
|
||||||
tcgetattr(kbd_fd, &term_orig);
|
tcgetattr(kbd_fd, &term_orig);
|
||||||
bb_signals(0
|
|
||||||
+ (1 << SIGTERM)
|
|
||||||
+ (1 << SIGINT)
|
|
||||||
, sig_catcher);
|
|
||||||
term_less = term_orig;
|
term_less = term_orig;
|
||||||
term_less.c_lflag &= ~(ICANON | ECHO);
|
term_less.c_lflag &= ~(ICANON | ECHO);
|
||||||
term_less.c_iflag &= ~(IXON | ICRNL);
|
term_less.c_iflag &= ~(IXON | ICRNL);
|
||||||
@ -1366,10 +1383,6 @@ int less_main(int argc, char **argv)
|
|||||||
term_less.c_cc[VMIN] = 1;
|
term_less.c_cc[VMIN] = 1;
|
||||||
term_less.c_cc[VTIME] = 0;
|
term_less.c_cc[VTIME] = 0;
|
||||||
|
|
||||||
/* Want to do it just once, but it doesn't work, */
|
|
||||||
/* so we are redoing it (see code above). Mystery... */
|
|
||||||
/*tcsetattr(kbd_fd, TCSANOW, &term_less);*/
|
|
||||||
|
|
||||||
reinitialize();
|
reinitialize();
|
||||||
while (1) {
|
while (1) {
|
||||||
keypress = less_getch();
|
keypress = less_getch();
|
||||||
|
Loading…
Reference in New Issue
Block a user