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);
|
||||
|
||||
//enum {
|
||||
// BB_SIGS_FATAL = ,
|
||||
//};
|
||||
enum {
|
||||
/* 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));
|
||||
/* Unlike signal() and bb_signals, sets handler with sigaction()
|
||||
* and in a way that while signal handler is run, no other signals
|
||||
|
@ -90,6 +90,7 @@ enum { pattern_valid = 0 };
|
||||
struct globals {
|
||||
int cur_fline; /* signed */
|
||||
int kbd_fd; /* fd to get input from */
|
||||
int less_gets_pos;
|
||||
/* last position in last line, taking into account tabs */
|
||||
size_t linepos;
|
||||
unsigned max_displayed_line;
|
||||
@ -123,6 +124,7 @@ struct globals {
|
||||
#define G (*ptr_to_globals)
|
||||
#define cur_fline (G.cur_fline )
|
||||
#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 )
|
||||
@ -152,6 +154,7 @@ struct globals {
|
||||
#define term_less (G.term_less )
|
||||
#define INIT_G() do { \
|
||||
PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
|
||||
less_gets_pos = -1; \
|
||||
empty_line_marker = "~"; \
|
||||
num_files = 1; \
|
||||
current_file = 1; \
|
||||
@ -385,6 +388,9 @@ static void m_status_print(void)
|
||||
{
|
||||
int percentage;
|
||||
|
||||
if (less_gets_pos >= 0) /* don't touch statusline while input is done! */
|
||||
return;
|
||||
|
||||
clear_line();
|
||||
printf(HIGHLIGHT"%s", filename);
|
||||
if (num_files > 1)
|
||||
@ -408,6 +414,9 @@ static void status_print(void)
|
||||
{
|
||||
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 */
|
||||
#if ENABLE_FEATURE_LESS_FLAGS
|
||||
if (option_mask32 & (FLAG_M|FLAG_m)) {
|
||||
@ -652,43 +661,46 @@ static void reinitialize(void)
|
||||
buffer_fill_and_print();
|
||||
}
|
||||
|
||||
static void getch_nowait(char* input, int sz)
|
||||
static ssize_t getch_nowait(char* input, int sz)
|
||||
{
|
||||
ssize_t rd;
|
||||
fd_set readfds;
|
||||
again:
|
||||
fflush(stdout);
|
||||
struct pollfd pfd[2];
|
||||
|
||||
/* NB: select returns whenever read will not block. Therefore:
|
||||
* (a) with O_NONBLOCK'ed fds select will return immediately
|
||||
* (b) if eof is reached, select will also return
|
||||
* because read will immediately return 0 bytes.
|
||||
* Even if select says that input is available, read CAN block
|
||||
pfd[0].fd = STDIN_FILENO;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = kbd_fd;
|
||||
pfd[1].events = POLLIN;
|
||||
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)
|
||||
*/
|
||||
FD_ZERO(&readfds);
|
||||
rd = 1;
|
||||
if (max_fline <= cur_fline + max_displayed_line
|
||||
&& eof_error > 0 /* did NOT reach eof yet */
|
||||
) {
|
||||
/* We are interested in stdin */
|
||||
FD_SET(0, &readfds);
|
||||
rd = 0;
|
||||
}
|
||||
FD_SET(kbd_fd, &readfds);
|
||||
tcsetattr(kbd_fd, TCSANOW, &term_less);
|
||||
select(kbd_fd + 1, &readfds, NULL, NULL, NULL);
|
||||
/* position cursor if line input is done */
|
||||
if (less_gets_pos >= 0)
|
||||
move_cursor(max_displayed_line + 2, less_gets_pos + 1);
|
||||
fflush(stdout);
|
||||
safe_poll(pfd + rd, 2 - rd, -1);
|
||||
|
||||
input[0] = '\0';
|
||||
ndelay_on(kbd_fd);
|
||||
rd = read(kbd_fd, input, sz);
|
||||
ndelay_off(kbd_fd);
|
||||
if (rd < 0) {
|
||||
/* No keyboard input, but we have input on stdin! */
|
||||
if (errno != EAGAIN) /* Huh?? */
|
||||
return;
|
||||
rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */
|
||||
if (rd < 0 && errno == EAGAIN) {
|
||||
/* No keyboard input -> we have input on stdin! */
|
||||
read_lines();
|
||||
buffer_fill_and_print();
|
||||
goto again;
|
||||
}
|
||||
set_tty_cooked();
|
||||
return rd;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
static int less_getch(void)
|
||||
{
|
||||
char input[16];
|
||||
unsigned char input[16];
|
||||
unsigned i;
|
||||
again:
|
||||
memset(input, 0, sizeof(input));
|
||||
@ -705,7 +717,6 @@ static int less_getch(void)
|
||||
/* Detect escape sequences (i.e. arrow keys) and handle
|
||||
* them accordingly */
|
||||
if (input[0] == '\033' && input[1] == '[') {
|
||||
set_tty_cooked();
|
||||
i = input[2] - REAL_KEY_UP;
|
||||
if (i < 4)
|
||||
return 20 + i;
|
||||
@ -724,8 +735,8 @@ static int less_getch(void)
|
||||
}
|
||||
/* Reject almost all control chars */
|
||||
i = input[0];
|
||||
if (i < ' ' && i != 0x0d && i != 8) goto again;
|
||||
set_tty_cooked();
|
||||
if (i < ' ' && i != 0x0d && i != 8)
|
||||
goto again;
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -734,22 +745,21 @@ static char* less_gets(int sz)
|
||||
char c;
|
||||
int i = 0;
|
||||
char *result = xzalloc(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';
|
||||
read(kbd_fd, &c, 1);
|
||||
if (c == 0x0d)
|
||||
less_gets_pos = sz + i;
|
||||
getch_nowait(&c, 1);
|
||||
if (c == 0x0d) {
|
||||
less_gets_pos = -1;
|
||||
return result;
|
||||
}
|
||||
if (c == 0x7f)
|
||||
c = 8;
|
||||
if (c == 8 && i) {
|
||||
printf("\x8 \x8");
|
||||
i--;
|
||||
result[i] = '\0';
|
||||
}
|
||||
if (c < ' ')
|
||||
continue;
|
||||
@ -764,9 +774,17 @@ static char* less_gets(int sz)
|
||||
|
||||
static void examine_file(void)
|
||||
{
|
||||
char *new_fname;
|
||||
|
||||
print_statusline("Examine: ");
|
||||
new_fname = less_gets(sizeof("Examine: ")-1);
|
||||
if (!new_fname[0]) {
|
||||
free(new_fname);
|
||||
status_print();
|
||||
return;
|
||||
}
|
||||
free(filename);
|
||||
filename = less_gets(sizeof("Examine: ")-1);
|
||||
filename = new_fname;
|
||||
/* files start by = argv. why we assume that argv is infinitely long??
|
||||
files[num_files] = filename;
|
||||
current_file = num_files + 1;
|
||||
@ -1087,7 +1105,7 @@ static void save_input_to_file(void)
|
||||
|
||||
print_statusline("Log file: ");
|
||||
current_line = less_gets(sizeof("Log file: ")-1);
|
||||
if (strlen(current_line) > 0) {
|
||||
if (current_line[0]) {
|
||||
fp = fopen(current_line, "w");
|
||||
if (!fp) {
|
||||
msg = "Error opening log file";
|
||||
@ -1334,6 +1352,7 @@ int less_main(int argc, char **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)) {
|
||||
@ -1354,11 +1373,9 @@ int less_main(int argc, char **argv)
|
||||
if (option_mask32 & FLAG_TILDE)
|
||||
empty_line_marker = "";
|
||||
|
||||
bb_signals(BB_SIGS_FATAL, sig_catcher);
|
||||
|
||||
tcgetattr(kbd_fd, &term_orig);
|
||||
bb_signals(0
|
||||
+ (1 << SIGTERM)
|
||||
+ (1 << SIGINT)
|
||||
, sig_catcher);
|
||||
term_less = term_orig;
|
||||
term_less.c_lflag &= ~(ICANON | ECHO);
|
||||
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[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();
|
||||
while (1) {
|
||||
keypress = less_getch();
|
||||
|
Loading…
Reference in New Issue
Block a user