diff options
Diffstat (limited to 'drivers/tty/vt/selection.c')
-rw-r--r-- | drivers/tty/vt/selection.c | 133 |
1 files changed, 72 insertions, 61 deletions
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index d54a549c5892..31bb3647a99c 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -185,47 +185,54 @@ int set_selection_user(const struct tiocl_selection __user *sel, return set_selection_kernel(&v, tty); } -static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) +static int vc_selection_store_chars(struct vc_data *vc, bool unicode) { - struct vc_data *vc = vc_cons[fg_console].d; - int new_sel_start, new_sel_end, spc; char *bp, *obp; - int i, ps, pe; - u32 c; - int ret = 0; - bool unicode; - - poke_blanked_console(); - - v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1); - v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1); - v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1); - v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1); - ps = v->ys * vc->vc_size_row + (v->xs << 1); - pe = v->ye * vc->vc_size_row + (v->xe << 1); + unsigned int i; - if (v->sel_mode == TIOCL_SELCLEAR) { - /* useful for screendump without selection highlights */ + /* Allocate a new buffer before freeing the old one ... */ + /* chars can take up to 4 bytes with unicode */ + bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, + GFP_KERNEL); + if (!bp) { + printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); - return 0; + return -ENOMEM; } + kfree(vc_sel.buffer); + vc_sel.buffer = bp; - if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) { - mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs, - v->ys); - return 0; + obp = bp; + for (i = vc_sel.start; i <= vc_sel.end; i += 2) { + u32 c = sel_pos(i, unicode); + if (unicode) + bp += store_utf8(c, bp); + else + *bp++ = c; + if (!isspace(c)) + obp = bp; + if (!((i + 2) % vc->vc_size_row)) { + /* strip trailing blanks from line and add newline, + unless non-space at end of line. */ + if (obp != bp) { + bp = obp; + *bp++ = '\r'; + } + obp = bp; + } } + vc_sel.buf_len = bp - vc_sel.buffer; - if (ps > pe) /* make vc_sel.start <= vc_sel.end */ - swap(ps, pe); + return 0; +} - if (vc_sel.cons != vc_cons[fg_console].d) { - clear_selection(); - vc_sel.cons = vc_cons[fg_console].d; - } - unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; +static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, + int pe) +{ + int new_sel_start, new_sel_end, spc; + bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; - switch (v->sel_mode) { + switch (mode) { case TIOCL_SELCHAR: /* character-by-character selection */ new_sel_start = ps; new_sel_end = pe; @@ -303,40 +310,44 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct * vc_sel.start = new_sel_start; vc_sel.end = new_sel_end; - /* Allocate a new buffer before freeing the old one ... */ - /* chars can take up to 4 bytes with unicode */ - bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, - GFP_KERNEL); - if (!bp) { - printk(KERN_WARNING "selection: kmalloc() failed\n"); + return vc_selection_store_chars(vc, unicode); +} + +static int vc_selection(struct vc_data *vc, struct tiocl_selection *v, + struct tty_struct *tty) +{ + int ps, pe; + + poke_blanked_console(); + + if (v->sel_mode == TIOCL_SELCLEAR) { + /* useful for screendump without selection highlights */ clear_selection(); - return -ENOMEM; + return 0; } - kfree(vc_sel.buffer); - vc_sel.buffer = bp; - obp = bp; - for (i = vc_sel.start; i <= vc_sel.end; i += 2) { - c = sel_pos(i, unicode); - if (unicode) - bp += store_utf8(c, bp); - else - *bp++ = c; - if (!isspace(c)) - obp = bp; - if (! ((i + 2) % vc->vc_size_row)) { - /* strip trailing blanks from line and add newline, - unless non-space at end of line. */ - if (obp != bp) { - bp = obp; - *bp++ = '\r'; - } - obp = bp; - } + v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1); + v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1); + v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1); + v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1); + + if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) { + mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs, + v->ys); + return 0; } - vc_sel.buf_len = bp - vc_sel.buffer; - return ret; + ps = v->ys * vc->vc_size_row + (v->xs << 1); + pe = v->ye * vc->vc_size_row + (v->xe << 1); + if (ps > pe) /* make vc_sel.start <= vc_sel.end */ + swap(ps, pe); + + if (vc_sel.cons != vc) { + clear_selection(); + vc_sel.cons = vc; + } + + return vc_do_selection(vc, v->sel_mode, ps, pe); } int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) @@ -345,7 +356,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) mutex_lock(&vc_sel.lock); console_lock(); - ret = __set_selection_kernel(v, tty); + ret = vc_selection(vc_cons[fg_console].d, v, tty); console_unlock(); mutex_unlock(&vc_sel.lock); |