Fix backspace in the virtual terminal when line is wrapped: 1) Add option for backspace to work when wrapped to next line by adding a new private mode 45 to enable reverse wrap (default: off). This matches xterm's behavior, which already supports private mode 45. 2) Correct the backspace behavior when the most recently typed character is in the rightmost column (i.e. in need_wrap state). Use high bit of need_wrap (now 2 bits) allow this backspace logic to work even when autowrap is off. Signed-off-by: Joe Peterson --- diff -Nurp a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c 2008-09-21 09:27:43.186681676 -0600 +++ b/drivers/char/vt.c 2008-09-21 09:15:30.826683557 -0600 @@ -1130,12 +1130,36 @@ static inline void cr(struct vc_data *vc static inline void bs(struct vc_data *vc) { - if (vc->vc_x) { - vc->vc_pos -= 2; - vc->vc_x--; + if (vc->vc_need_wrap) { + /* + * If in need_wrap state (regardless of autowrap mode), + * do not move cursor, but unset need_wrap. + */ vc->vc_need_wrap = 0; - notify_write(vc, '\b'); + } else { + if (vc->vc_x == 0) { + /* + * If at leftmost column, move cursor to end + * of previous line (only if reverse wrap is on). + */ + if (vc->vc_reverse_wrap) { + vc->vc_x = vc->vc_cols - 1; + if (vc->vc_y == vc->vc_top) { + scrdown(vc, + vc->vc_top, vc->vc_bottom, 1); + vc->vc_pos += vc->vc_size_row - 2; + } else if (vc->vc_y > 0) { + vc->vc_y--; + vc->vc_pos -= 2; + } + } + } else { + /* Normal case: just move cursor back */ + vc->vc_x--; + vc->vc_pos -= 2; + } } + notify_write(vc, '\b'); } static inline void del(struct vc_data *vc) @@ -1437,6 +1461,9 @@ static void set_mode(struct vc_data *vc, case 25: /* Cursor on/off */ vc->vc_deccm = on_off; break; + case 45: /* Reverse wrap on/off */ + vc->vc_reverse_wrap = on_off; + break; case 1000: vc->vc_report_mouse = on_off ? 2 : 0; break; @@ -1621,6 +1648,7 @@ static void reset_terminal(struct vc_dat vc->vc_decscnm = 0; vc->vc_decom = 0; vc->vc_decawm = 1; + vc->vc_reverse_wrap = 0; vc->vc_deccm = 1; vc->vc_decim = 0; @@ -2320,9 +2348,9 @@ rescan_last_byte: } while (1) { - if (vc->vc_need_wrap || vc->vc_decim) + if ((vc->vc_need_wrap & 1) || vc->vc_decim) FLUSH - if (vc->vc_need_wrap) { + if (vc->vc_need_wrap & 1) { cr(vc); lf(vc); } @@ -2337,7 +2365,12 @@ rescan_last_byte: draw_from = vc->vc_pos; } if (vc->vc_x == vc->vc_cols - 1) { - vc->vc_need_wrap = vc->vc_decawm; + /* + * Set high bit of need_wrap regardless + * of autowrap mode (backspace logic + * relies on this). + */ + vc->vc_need_wrap = 2 | vc->vc_decawm; draw_to = vc->vc_pos + 2; } else { vc->vc_x++; @@ -2496,12 +2529,12 @@ static void vt_console_print(struct cons * Problems caused when we have need_wrap set on '\n' character */ while (count--) { c = *b++; - if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { + if (c == 10 || c == 13 || c == 8 || (vc->vc_need_wrap & 1)) { if (cnt > 0) { if (CON_IS_VISIBLE(vc)) vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_x += cnt; - if (vc->vc_need_wrap) + if (vc->vc_need_wrap & 1) vc->vc_x--; cnt = 0; } diff -Nurp a/include/linux/console_struct.h b/include/linux/console_struct.h --- a/include/linux/console_struct.h 2008-09-21 09:15:16.136681289 -0600 +++ b/include/linux/console_struct.h 2008-09-21 09:15:30.956686803 -0600 @@ -71,6 +71,7 @@ struct vc_data { unsigned int vc_decscnm : 1; /* Screen Mode */ unsigned int vc_decom : 1; /* Origin Mode */ unsigned int vc_decawm : 1; /* Autowrap Mode */ + unsigned int vc_reverse_wrap : 1; /* Reverse wrap Mode */ unsigned int vc_deccm : 1; /* Cursor Visible */ unsigned int vc_decim : 1; /* Insert Mode */ unsigned int vc_deccolm : 1; /* 80/132 Column Mode */ @@ -87,7 +88,7 @@ struct vc_data { unsigned int vc_s_reverse : 1; /* misc */ unsigned int vc_ques : 1; - unsigned int vc_need_wrap : 1; + unsigned int vc_need_wrap : 2; unsigned int vc_can_do_color : 1; unsigned int vc_report_mouse : 2; unsigned int vc_kmalloced : 1;