lineedit: fix two bugs in SIGWINCH signal handling
(1) restore entire sigaction, not only signal handler function (2) do not use stdio when not sure WINCH did not interrupt a printf() or such. function old new delta cmdedit_setwidth - 81 +81 read_line_input 3682 3722 +40 lineedit_read_key 138 155 +17 put_prompt 55 51 -4 win_changed 93 47 -46 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 138/-50) Total: 88 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
710b6ce9b0
commit
bff71d3b9d
@ -129,8 +129,7 @@ static const char null_str[] ALIGN1 = "";
|
|||||||
struct lineedit_statics {
|
struct lineedit_statics {
|
||||||
line_input_t *state;
|
line_input_t *state;
|
||||||
|
|
||||||
volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
|
unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
|
||||||
sighandler_t previous_SIGWINCH_handler;
|
|
||||||
|
|
||||||
unsigned cmdedit_x; /* real x (col) terminal position */
|
unsigned cmdedit_x; /* real x (col) terminal position */
|
||||||
unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
|
unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
|
||||||
@ -155,15 +154,22 @@ struct lineedit_statics {
|
|||||||
unsigned num_matches;
|
unsigned num_matches;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
unsigned SIGWINCH_saved;
|
||||||
|
volatile unsigned SIGWINCH_count;
|
||||||
|
volatile smallint ok_to_redraw;
|
||||||
|
|
||||||
#if ENABLE_FEATURE_EDITING_VI
|
#if ENABLE_FEATURE_EDITING_VI
|
||||||
# define DELBUFSIZ 128
|
# define DELBUFSIZ 128
|
||||||
CHAR_T *delptr;
|
|
||||||
smallint newdelflag; /* whether delbuf should be reused yet */
|
smallint newdelflag; /* whether delbuf should be reused yet */
|
||||||
|
CHAR_T *delptr;
|
||||||
CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
|
CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */
|
||||||
#endif
|
#endif
|
||||||
#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
|
#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
|
||||||
smallint sent_ESC_br6n;
|
smallint sent_ESC_br6n;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Largish struct, keeping it last results in smaller code */
|
||||||
|
struct sigaction SIGWINCH_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* See lineedit_ptr_hack.c */
|
/* See lineedit_ptr_hack.c */
|
||||||
@ -172,7 +178,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
|
|||||||
#define S (*lineedit_ptr_to_statics)
|
#define S (*lineedit_ptr_to_statics)
|
||||||
#define state (S.state )
|
#define state (S.state )
|
||||||
#define cmdedit_termw (S.cmdedit_termw )
|
#define cmdedit_termw (S.cmdedit_termw )
|
||||||
#define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler)
|
|
||||||
#define cmdedit_x (S.cmdedit_x )
|
#define cmdedit_x (S.cmdedit_x )
|
||||||
#define cmdedit_y (S.cmdedit_y )
|
#define cmdedit_y (S.cmdedit_y )
|
||||||
#define cmdedit_prmt_len (S.cmdedit_prmt_len)
|
#define cmdedit_prmt_len (S.cmdedit_prmt_len)
|
||||||
@ -434,14 +439,11 @@ static void beep(void)
|
|||||||
|
|
||||||
static void put_prompt(void)
|
static void put_prompt(void)
|
||||||
{
|
{
|
||||||
unsigned w;
|
|
||||||
|
|
||||||
fputs(cmdedit_prompt, stdout);
|
fputs(cmdedit_prompt, stdout);
|
||||||
fflush_all();
|
fflush_all();
|
||||||
cursor = 0;
|
cursor = 0;
|
||||||
w = cmdedit_termw; /* read volatile var once */
|
cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */
|
||||||
cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */
|
cmdedit_x = cmdedit_prmt_len % cmdedit_termw;
|
||||||
cmdedit_x = cmdedit_prmt_len % w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move back one character */
|
/* Move back one character */
|
||||||
@ -513,13 +515,11 @@ static void input_backward(unsigned num)
|
|||||||
put_cur_glyph_and_inc_cursor();
|
put_cur_glyph_and_inc_cursor();
|
||||||
} else {
|
} else {
|
||||||
int lines_up;
|
int lines_up;
|
||||||
unsigned width;
|
|
||||||
/* num = chars to go back from the beginning of current line: */
|
/* num = chars to go back from the beginning of current line: */
|
||||||
num -= cmdedit_x;
|
num -= cmdedit_x;
|
||||||
width = cmdedit_termw; /* read volatile var once */
|
|
||||||
/* num=1...w: one line up, w+1...2w: two, etc: */
|
/* num=1...w: one line up, w+1...2w: two, etc: */
|
||||||
lines_up = 1 + (num - 1) / width;
|
lines_up = 1 + (num - 1) / cmdedit_termw;
|
||||||
cmdedit_x = (width * cmdedit_y - num) % width;
|
cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw;
|
||||||
cmdedit_y -= lines_up;
|
cmdedit_y -= lines_up;
|
||||||
/* go to 1st column; go up */
|
/* go to 1st column; go up */
|
||||||
printf("\r" ESC"[%uA", lines_up);
|
printf("\r" ESC"[%uA", lines_up);
|
||||||
@ -1978,28 +1978,29 @@ static void parse_and_put_prompt(const char *prmt_ptr)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void cmdedit_setwidth(unsigned w, int redraw_flg)
|
static void cmdedit_setwidth(int redraw_flg)
|
||||||
{
|
{
|
||||||
cmdedit_termw = w;
|
get_terminal_width_height(STDIN_FILENO, &cmdedit_termw, NULL);
|
||||||
if (redraw_flg) {
|
if (redraw_flg) {
|
||||||
/* new y for current cursor */
|
/* new y for current cursor */
|
||||||
int new_y = (cursor + cmdedit_prmt_len) / w;
|
int new_y = (cursor + cmdedit_prmt_len) / cmdedit_termw;
|
||||||
/* redraw */
|
/* redraw */
|
||||||
redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
|
redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor);
|
||||||
fflush_all();
|
fflush_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void win_changed(int nsig)
|
static void win_changed(int nsig UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
int sv_errno = errno;
|
if (S.ok_to_redraw) {
|
||||||
unsigned width;
|
/* We are in read_key(), safe to redraw immediately */
|
||||||
|
int sv_errno = errno;
|
||||||
get_terminal_width_height(0, &width, NULL);
|
cmdedit_setwidth(/*redraw_flg:*/ 1);
|
||||||
//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!)
|
errno = sv_errno;
|
||||||
cmdedit_setwidth(width, /*redraw_flg:*/ nsig);
|
} else {
|
||||||
|
/* Signal main loop that redraw is necessary */
|
||||||
errno = sv_errno;
|
S.SIGWINCH_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lineedit_read_key(char *read_key_buffer, int timeout)
|
static int lineedit_read_key(char *read_key_buffer, int timeout)
|
||||||
@ -2018,7 +2019,9 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
|
|||||||
*
|
*
|
||||||
* Note: read_key sets errno to 0 on success.
|
* Note: read_key sets errno to 0 on success.
|
||||||
*/
|
*/
|
||||||
|
S.ok_to_redraw = 1;
|
||||||
ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
|
ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
|
||||||
|
S.ok_to_redraw = 0;
|
||||||
if (errno) {
|
if (errno) {
|
||||||
#if ENABLE_UNICODE_SUPPORT
|
#if ENABLE_UNICODE_SUPPORT
|
||||||
if (errno == EAGAIN && unicode_idx != 0)
|
if (errno == EAGAIN && unicode_idx != 0)
|
||||||
@ -2355,9 +2358,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
|
|||||||
ask_terminal();
|
ask_terminal();
|
||||||
|
|
||||||
/* Install window resize handler (NB: after *all* init is complete) */
|
/* Install window resize handler (NB: after *all* init is complete) */
|
||||||
//FIXME: save entire sigaction!
|
S.SIGWINCH_handler.sa_handler = win_changed;
|
||||||
previous_SIGWINCH_handler = signal(SIGWINCH, win_changed);
|
S.SIGWINCH_handler.sa_flags = SA_RESTART;
|
||||||
win_changed(0); /* get initial window size */
|
sigaction(SIGWINCH, &S.SIGWINCH_handler, &S.SIGWINCH_handler);
|
||||||
|
|
||||||
|
cmdedit_setwidth(/*redraw_flg:*/ 0); /* get initial window size */
|
||||||
|
|
||||||
read_key_buffer[0] = 0;
|
read_key_buffer[0] = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -2370,6 +2375,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
|
|||||||
* in one place.
|
* in one place.
|
||||||
*/
|
*/
|
||||||
int32_t ic, ic_raw;
|
int32_t ic, ic_raw;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
count = S.SIGWINCH_count;
|
||||||
|
if (S.SIGWINCH_saved != count) {
|
||||||
|
S.SIGWINCH_saved = count;
|
||||||
|
cmdedit_setwidth(/*redraw_flg:*/ 1);
|
||||||
|
}
|
||||||
|
|
||||||
fflush_all();
|
fflush_all();
|
||||||
ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
|
ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
|
||||||
@ -2808,7 +2820,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
|
|||||||
/* restore initial_settings */
|
/* restore initial_settings */
|
||||||
tcsetattr_stdin_TCSANOW(&initial_settings);
|
tcsetattr_stdin_TCSANOW(&initial_settings);
|
||||||
/* restore SIGWINCH handler */
|
/* restore SIGWINCH handler */
|
||||||
signal(SIGWINCH, previous_SIGWINCH_handler);
|
sigaction_set(SIGWINCH, &S.SIGWINCH_handler);
|
||||||
fflush_all();
|
fflush_all();
|
||||||
|
|
||||||
len = command_len;
|
len = command_len;
|
||||||
|
Loading…
Reference in New Issue
Block a user