/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ #define is_space_on_vt(c) ((c) == ' ')
/* FIXME: all this needs locking */ staticstruct vc_selection { struct mutex lock; struct vc_data *cons; /* must not be deallocated */ char *buffer; unsignedint buf_len; volatileint start; /* cleared by clear_selection */ int end;
} vc_sel = {
.lock = __MUTEX_INITIALIZER(vc_sel.lock),
.start = -1,
};
/* clear_selection, highlight and highlight_pointer can be called
from interrupt (via scrollback/front) */
/* set reverse video on characters s-e of console with selection. */ staticinlinevoid highlight(constint s, constint e)
{
invert_screen(vc_sel.cons, s, e-s+2, true);
}
/* use complementary color to show the pointer */ staticinlinevoid highlight_pointer(constint where)
{
complement_pos(vc_sel.cons, where);
}
static u32
sel_pos(int n, bool unicode)
{ if (unicode) return screen_glyph_unicode(vc_sel.cons, n / 2); return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), false);
}
/** * clear_selection - remove current selection * * Remove the current selection highlight, if any from the console holding the * selection. * * Locking: The caller must hold the console lock.
*/ void clear_selection(void)
{
highlight_pointer(-1); /* hide the pointer */ if (vc_sel.start != -1) {
highlight(vc_sel.start, vc_sel.end);
vc_sel.start = -1;
}
}
EXPORT_SYMBOL_GPL(clear_selection);
/* * User settable table: what characters are to be considered alphabetic? * 128 bits. Locked by the console lock.
*/ static u32 inwordLut[]={
0x00000000, /* control chars */
0x03FFE000, /* digits and "-./" */
0x87FFFFFE, /* uppercase and '_' */
0x07FFFFFE, /* lowercase */
};
staticinlineint inword(const u32 c)
{ return c > 0x7f || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
}
/** * sel_loadlut() - load the LUT table * @lut: user table * * Load the LUT table from user space. Make a temporary copy so a partial * update doesn't make a mess. * * Locking: The console lock is acquired.
*/ int sel_loadlut(u32 __user *lut)
{
u32 tmplut[ARRAY_SIZE(inwordLut)];
if (copy_from_user(tmplut, lut, sizeof(inwordLut))) return -EFAULT;
/* does screen address p correspond to character at LH/RH edge of screen? */ staticinlineint atedge(constint p, int size_row)
{ return (!(p % size_row) || !((p + 2) % size_row));
}
/** * set_selection_user - set the current selection. * @sel: user selection info * @tty: the console tty * * Invoked by the ioctl handle for the vt layer. * * Locking: The entire selection process is managed under the console_lock. * It's a lot under the lock but its hardly a performance path.
*/ int set_selection_user(conststruct tiocl_selection __user *sel, struct tty_struct *tty)
{ struct tiocl_selection v;
if (copy_from_user(&v, sel, sizeof(*sel))) return -EFAULT;
/* * TIOCL_SELCLEAR and TIOCL_SELPOINTER are OK to use without * CAP_SYS_ADMIN as they do not modify the selection.
*/ switch (v.sel_mode) { case TIOCL_SELCLEAR: case TIOCL_SELPOINTER: break; default: if (!capable(CAP_SYS_ADMIN)) return -EPERM;
}
/* 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 | __GFP_NOWARN); if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection(); return -ENOMEM;
}
kfree(vc_sel.buffer);
vc_sel.buffer = bp;
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 (!is_space_on_vt(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;
return 0;
}
staticint vc_do_selection(struct vc_data *vc, unsignedshort mode, int ps, int pe)
{ int new_sel_start, new_sel_end, spc; bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE;
/* select to end of line if on trailing space */ if (new_sel_end > new_sel_start &&
!atedge(new_sel_end, vc->vc_size_row) &&
is_space_on_vt(sel_pos(new_sel_end, unicode))) { for (pe = new_sel_end + 2; ; pe += 2) if (!is_space_on_vt(sel_pos(pe, unicode)) ||
atedge(pe, vc->vc_size_row)) break; if (is_space_on_vt(sel_pos(pe, unicode)))
new_sel_end = pe;
} if (vc_sel.start == -1) /* no current selection */
highlight(new_sel_start, new_sel_end); elseif (new_sel_start == vc_sel.start)
{ if (new_sel_end == vc_sel.end) /* no action required */ return 0; elseif (new_sel_end > vc_sel.end) /* extend to right */
highlight(vc_sel.end + 2, new_sel_end); else/* contract from right */
highlight(new_sel_end + 2, vc_sel.end);
} elseif (new_sel_end == vc_sel.end)
{ if (new_sel_start < vc_sel.start) /* extend to left */
highlight(new_sel_start, vc_sel.start - 2); else/* contract from left */
highlight(vc_sel.start, new_sel_start - 2);
} else/* some other case; start selection from scratch */
{
clear_selection();
highlight(new_sel_start, new_sel_end);
}
vc_sel.start = new_sel_start;
vc_sel.end = new_sel_end;
/* Insert the contents of the selection buffer into the * queue of the tty associated with the current console. * Invoked by ioctl(). * * Locking: called without locks. Calls the ldisc wrongly with * unsafe methods,
*/ int paste_selection(struct tty_struct *tty)
{ struct vc_data *vc = tty->driver_data; int pasted = 0;
size_t count; struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current); int ret = 0;
bool bp = vc->vc_bracketed_paste; staticconstchar bracketed_paste_start[] = "\033[200~"; staticconstchar bracketed_paste_end[] = "\033[201~"; constchar *bps = bp ? bracketed_paste_start : NULL; constchar *bpe = bp ? bracketed_paste_end : NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.