1 /* 2 * This module exports the functions: 3 * 4 * 'int set_selection(struct tiocl_selection __user *, struct tty_struct *)' 5 * 'void clear_selection(void)' 6 * 'int paste_selection(struct tty_struct *)' 7 * 'int sel_loadlut(char __user *)' 8 * 9 * Now that /dev/vcs exists, most of this can disappear again. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/tty.h> 14 #include <linux/sched.h> 15 #include <linux/mm.h> 16 #include <linux/slab.h> 17 #include <linux/types.h> 18 19 #include <asm/uaccess.h> 20 21 #include <linux/kbd_kern.h> 22 #include <linux/vt_kern.h> 23 #include <linux/consolemap.h> 24 #include <linux/selection.h> 25 #include <linux/tiocl.h> 26 #include <linux/console.h> 27 #include <linux/tty_flip.h> 28 29 /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ 30 #define isspace(c) ((c) == ' ') 31 32 extern void poke_blanked_console(void); 33 34 /* FIXME: all this needs locking */ 35 /* Variables for selection control. */ 36 /* Use a dynamic buffer, instead of static (Dec 1994) */ 37 struct vc_data *sel_cons; /* must not be deallocated */ 38 static int use_unicode; 39 static volatile int sel_start = -1; /* cleared by clear_selection */ 40 static int sel_end; 41 static int sel_buffer_lth; 42 static char *sel_buffer; 43 44 /* clear_selection, highlight and highlight_pointer can be called 45 from interrupt (via scrollback/front) */ 46 47 /* set reverse video on characters s-e of console with selection. */ 48 static inline void highlight(const int s, const int e) 49 { 50 invert_screen(sel_cons, s, e-s+2, 1); 51 } 52 53 /* use complementary color to show the pointer */ 54 static inline void highlight_pointer(const int where) 55 { 56 complement_pos(sel_cons, where); 57 } 58 59 static u16 60 sel_pos(int n) 61 { 62 return inverse_translate(sel_cons, screen_glyph(sel_cons, n), 63 use_unicode); 64 } 65 66 /** 67 * clear_selection - remove current selection 68 * 69 * Remove the current selection highlight, if any from the console 70 * holding the selection. The caller must hold the console lock. 71 */ 72 void clear_selection(void) 73 { 74 highlight_pointer(-1); /* hide the pointer */ 75 if (sel_start != -1) { 76 highlight(sel_start, sel_end); 77 sel_start = -1; 78 } 79 } 80 81 /* 82 * User settable table: what characters are to be considered alphabetic? 83 * 256 bits. Locked by the console lock. 84 */ 85 static u32 inwordLut[8]={ 86 0x00000000, /* control chars */ 87 0x03FF0000, /* digits */ 88 0x87FFFFFE, /* uppercase and '_' */ 89 0x07FFFFFE, /* lowercase */ 90 0x00000000, 91 0x00000000, 92 0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */ 93 0xFF7FFFFF /* latin-1 accented letters, not division sign */ 94 }; 95 96 static inline int inword(const u16 c) { 97 return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); 98 } 99 100 /** 101 * set loadlut - load the LUT table 102 * @p: user table 103 * 104 * Load the LUT table from user space. The caller must hold the console 105 * lock. Make a temporary copy so a partial update doesn't make a mess. 106 */ 107 int sel_loadlut(char __user *p) 108 { 109 u32 tmplut[8]; 110 if (copy_from_user(tmplut, (u32 __user *)(p+4), 32)) 111 return -EFAULT; 112 memcpy(inwordLut, tmplut, 32); 113 return 0; 114 } 115 116 /* does screen address p correspond to character at LH/RH edge of screen? */ 117 static inline int atedge(const int p, int size_row) 118 { 119 return (!(p % size_row) || !((p + 2) % size_row)); 120 } 121 122 /* constrain v such that v <= u */ 123 static inline unsigned short limit(const unsigned short v, const unsigned short u) 124 { 125 return (v > u) ? u : v; 126 } 127 128 /* stores the char in UTF8 and returns the number of bytes used (1-3) */ 129 static int store_utf8(u16 c, char *p) 130 { 131 if (c < 0x80) { 132 /* 0******* */ 133 p[0] = c; 134 return 1; 135 } else if (c < 0x800) { 136 /* 110***** 10****** */ 137 p[0] = 0xc0 | (c >> 6); 138 p[1] = 0x80 | (c & 0x3f); 139 return 2; 140 } else { 141 /* 1110**** 10****** 10****** */ 142 p[0] = 0xe0 | (c >> 12); 143 p[1] = 0x80 | ((c >> 6) & 0x3f); 144 p[2] = 0x80 | (c & 0x3f); 145 return 3; 146 } 147 } 148 149 /** 150 * set_selection - set the current selection. 151 * @sel: user selection info 152 * @tty: the console tty 153 * 154 * Invoked by the ioctl handle for the vt layer. 155 * 156 * The entire selection process is managed under the console_lock. It's 157 * a lot under the lock but its hardly a performance path 158 */ 159 int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) 160 { 161 struct vc_data *vc = vc_cons[fg_console].d; 162 int sel_mode, new_sel_start, new_sel_end, spc; 163 char *bp, *obp; 164 int i, ps, pe, multiplier; 165 u16 c; 166 int mode; 167 168 poke_blanked_console(); 169 170 { unsigned short xs, ys, xe, ye; 171 172 if (!access_ok(VERIFY_READ, sel, sizeof(*sel))) 173 return -EFAULT; 174 __get_user(xs, &sel->xs); 175 __get_user(ys, &sel->ys); 176 __get_user(xe, &sel->xe); 177 __get_user(ye, &sel->ye); 178 __get_user(sel_mode, &sel->sel_mode); 179 xs--; ys--; xe--; ye--; 180 xs = limit(xs, vc->vc_cols - 1); 181 ys = limit(ys, vc->vc_rows - 1); 182 xe = limit(xe, vc->vc_cols - 1); 183 ye = limit(ye, vc->vc_rows - 1); 184 ps = ys * vc->vc_size_row + (xs << 1); 185 pe = ye * vc->vc_size_row + (xe << 1); 186 187 if (sel_mode == TIOCL_SELCLEAR) { 188 /* useful for screendump without selection highlights */ 189 clear_selection(); 190 return 0; 191 } 192 193 if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) { 194 mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys); 195 return 0; 196 } 197 } 198 199 if (ps > pe) /* make sel_start <= sel_end */ 200 { 201 int tmp = ps; 202 ps = pe; 203 pe = tmp; 204 } 205 206 if (sel_cons != vc_cons[fg_console].d) { 207 clear_selection(); 208 sel_cons = vc_cons[fg_console].d; 209 } 210 mode = vt_do_kdgkbmode(fg_console); 211 if (mode == K_UNICODE) 212 use_unicode = 1; 213 else 214 use_unicode = 0; 215 216 switch (sel_mode) 217 { 218 case TIOCL_SELCHAR: /* character-by-character selection */ 219 new_sel_start = ps; 220 new_sel_end = pe; 221 break; 222 case TIOCL_SELWORD: /* word-by-word selection */ 223 spc = isspace(sel_pos(ps)); 224 for (new_sel_start = ps; ; ps -= 2) 225 { 226 if ((spc && !isspace(sel_pos(ps))) || 227 (!spc && !inword(sel_pos(ps)))) 228 break; 229 new_sel_start = ps; 230 if (!(ps % vc->vc_size_row)) 231 break; 232 } 233 spc = isspace(sel_pos(pe)); 234 for (new_sel_end = pe; ; pe += 2) 235 { 236 if ((spc && !isspace(sel_pos(pe))) || 237 (!spc && !inword(sel_pos(pe)))) 238 break; 239 new_sel_end = pe; 240 if (!((pe + 2) % vc->vc_size_row)) 241 break; 242 } 243 break; 244 case TIOCL_SELLINE: /* line-by-line selection */ 245 new_sel_start = ps - ps % vc->vc_size_row; 246 new_sel_end = pe + vc->vc_size_row 247 - pe % vc->vc_size_row - 2; 248 break; 249 case TIOCL_SELPOINTER: 250 highlight_pointer(pe); 251 return 0; 252 default: 253 return -EINVAL; 254 } 255 256 /* remove the pointer */ 257 highlight_pointer(-1); 258 259 /* select to end of line if on trailing space */ 260 if (new_sel_end > new_sel_start && 261 !atedge(new_sel_end, vc->vc_size_row) && 262 isspace(sel_pos(new_sel_end))) { 263 for (pe = new_sel_end + 2; ; pe += 2) 264 if (!isspace(sel_pos(pe)) || 265 atedge(pe, vc->vc_size_row)) 266 break; 267 if (isspace(sel_pos(pe))) 268 new_sel_end = pe; 269 } 270 if (sel_start == -1) /* no current selection */ 271 highlight(new_sel_start, new_sel_end); 272 else if (new_sel_start == sel_start) 273 { 274 if (new_sel_end == sel_end) /* no action required */ 275 return 0; 276 else if (new_sel_end > sel_end) /* extend to right */ 277 highlight(sel_end + 2, new_sel_end); 278 else /* contract from right */ 279 highlight(new_sel_end + 2, sel_end); 280 } 281 else if (new_sel_end == sel_end) 282 { 283 if (new_sel_start < sel_start) /* extend to left */ 284 highlight(new_sel_start, sel_start - 2); 285 else /* contract from left */ 286 highlight(sel_start, new_sel_start - 2); 287 } 288 else /* some other case; start selection from scratch */ 289 { 290 clear_selection(); 291 highlight(new_sel_start, new_sel_end); 292 } 293 sel_start = new_sel_start; 294 sel_end = new_sel_end; 295 296 /* Allocate a new buffer before freeing the old one ... */ 297 multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ 298 bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL); 299 if (!bp) { 300 printk(KERN_WARNING "selection: kmalloc() failed\n"); 301 clear_selection(); 302 return -ENOMEM; 303 } 304 kfree(sel_buffer); 305 sel_buffer = bp; 306 307 obp = bp; 308 for (i = sel_start; i <= sel_end; i += 2) { 309 c = sel_pos(i); 310 if (use_unicode) 311 bp += store_utf8(c, bp); 312 else 313 *bp++ = c; 314 if (!isspace(c)) 315 obp = bp; 316 if (! ((i + 2) % vc->vc_size_row)) { 317 /* strip trailing blanks from line and add newline, 318 unless non-space at end of line. */ 319 if (obp != bp) { 320 bp = obp; 321 *bp++ = '\r'; 322 } 323 obp = bp; 324 } 325 } 326 sel_buffer_lth = bp - sel_buffer; 327 return 0; 328 } 329 330 /* Insert the contents of the selection buffer into the 331 * queue of the tty associated with the current console. 332 * Invoked by ioctl(). 333 * 334 * Locking: called without locks. Calls the ldisc wrongly with 335 * unsafe methods, 336 */ 337 int paste_selection(struct tty_struct *tty) 338 { 339 struct vc_data *vc = tty->driver_data; 340 int pasted = 0; 341 unsigned int count; 342 struct tty_ldisc *ld; 343 DECLARE_WAITQUEUE(wait, current); 344 345 console_lock(); 346 poke_blanked_console(); 347 console_unlock(); 348 349 ld = tty_ldisc_ref_wait(tty); 350 tty_buffer_lock_exclusive(&vc->port); 351 352 add_wait_queue(&vc->paste_wait, &wait); 353 while (sel_buffer && sel_buffer_lth > pasted) { 354 set_current_state(TASK_INTERRUPTIBLE); 355 if (test_bit(TTY_THROTTLED, &tty->flags)) { 356 schedule(); 357 continue; 358 } 359 count = sel_buffer_lth - pasted; 360 count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, 361 count); 362 pasted += count; 363 } 364 remove_wait_queue(&vc->paste_wait, &wait); 365 __set_current_state(TASK_RUNNING); 366 367 tty_buffer_unlock_exclusive(&vc->port); 368 tty_ldisc_deref(ld); 369 return 0; 370 } 371