root/drivers/char/selection.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. highlight
  2. highlight_pointer
  3. clear_selection
  4. inword
  5. sel_loadlut
  6. atedge
  7. limit
  8. set_selection
  9. paste_selection

   1 /*
   2  * linux/drivers/char/selection.c
   3  *
   4  * This module exports the functions:
   5  *
   6  *     'int set_selection(const unsigned long arg)'
   7  *     'void clear_selection(void)'
   8  *     'int paste_selection(struct tty_struct *tty)'
   9  *     'int sel_loadlut(const unsigned long arg)'
  10  *
  11  * Now that /dev/vcs exists, most of this can disappear again.
  12  */
  13 
  14 #include <linux/tty.h>
  15 #include <linux/sched.h>
  16 #include <linux/mm.h>
  17 #include <linux/malloc.h>
  18 #include <linux/types.h>
  19 
  20 #include <asm/segment.h>
  21 
  22 #include "vt_kern.h"
  23 #include "consolemap.h"
  24 #include "selection.h"
  25 
  26 #ifndef MIN
  27 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
  28 #endif
  29 
  30 /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
  31 #define isspace(c)      ((c) == ' ')
  32 
  33 /* Variables for selection control. */
  34 /* Use a dynamic buffer, instead of static (Dec 1994) */
  35        int sel_cons = 0;                /* must not be disallocated */
  36 static volatile int sel_start = -1;     /* cleared by clear_selection */
  37 static int sel_end;
  38 static int sel_buffer_lth = 0;
  39 static char *sel_buffer = NULL;
  40 
  41 #define sel_pos(n)   inverse_translate(scrw2glyph(screen_word(sel_cons, n, 1)))
  42 
  43 /* clear_selection, highlight and highlight_pointer can be called
  44    from interrupt (via scrollback/front) */
  45 
  46 /* set reverse video on characters s-e of console with selection. */
  47 inline static void
  48 highlight(const int s, const int e) {
     /* [previous][next][first][last][top][bottom][index][help] */
  49         invert_screen(sel_cons, s, e-s+2, 1);
  50 }
  51 
  52 /* use complementary color to show the pointer */
  53 inline static void
  54 highlight_pointer(const int where) {
     /* [previous][next][first][last][top][bottom][index][help] */
  55         complement_pos(sel_cons, where);
  56 }
  57 
  58 /* remove the current selection highlight, if any,
  59    from the console holding the selection. */
  60 void
  61 clear_selection(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
  62         highlight_pointer(-1); /* hide the pointer */
  63         if (sel_start != -1) {
  64                 highlight(sel_start, sel_end);
  65                 sel_start = -1;
  66         }
  67 }
  68 
  69 /*
  70  * User settable table: what characters are to be considered alphabetic?
  71  * 256 bits
  72  */
  73 static u32 inwordLut[8]={
  74   0x00000000, /* control chars     */
  75   0x03FF0000, /* digits            */
  76   0x87FFFFFE, /* uppercase and '_' */
  77   0x07FFFFFE, /* lowercase         */
  78   0x00000000,
  79   0x00000000,
  80   0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
  81   0xFF7FFFFF  /* latin-1 accented letters, not division sign */
  82 };
  83 
  84 static inline int inword(const unsigned char c) {
     /* [previous][next][first][last][top][bottom][index][help] */
  85         return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
  86 }
  87 
  88 /* set inwordLut contents. Invoked by ioctl(). */
  89 int sel_loadlut(const unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         int i = verify_area(VERIFY_READ, (char *) arg, 36);
  92         if (i)
  93                 return i;
  94         memcpy_fromfs(inwordLut, (u32 *)(arg+4), 32);
  95         return 0;
  96 }
  97 
  98 /* does screen address p correspond to character at LH/RH edge of screen? */
  99 static inline int atedge(const int p)
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101         return (!(p % video_size_row) || !((p + 2) % video_size_row));
 102 }
 103 
 104 /* constrain v such that v <= u */
 105 static inline unsigned short limit(const unsigned short v, const unsigned short u)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107 /* gcc miscompiles the ?: operator, so don't use it.. */
 108         if (v > u)
 109                 return u;
 110         return v;
 111 }
 112 
 113 /* set the current selection. Invoked by ioctl(). */
 114 int set_selection(const unsigned long arg, struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116         int sel_mode, new_sel_start, new_sel_end, spc;
 117         char *bp, *obp;
 118         int i, ps, pe;
 119 
 120         do_unblank_screen();
 121 
 122         { unsigned short *args, xs, ys, xe, ye;
 123 
 124           args = (unsigned short *)(arg + 1);
 125           xs = get_user(args++) - 1;
 126           ys = get_user(args++) - 1;
 127           xe = get_user(args++) - 1;
 128           ye = get_user(args++) - 1;
 129           sel_mode = get_user(args);
 130 
 131           xs = limit(xs, video_num_columns - 1);
 132           ys = limit(ys, video_num_lines - 1);
 133           xe = limit(xe, video_num_columns - 1);
 134           ye = limit(ye, video_num_lines - 1);
 135           ps = ys * video_size_row + (xs << 1);
 136           pe = ye * video_size_row + (xe << 1);
 137 
 138           if (sel_mode == 4) {
 139               /* useful for screendump without selection highlights */
 140               clear_selection();
 141               return 0;
 142           }
 143 
 144           if (mouse_reporting() && (sel_mode & 16)) {
 145               mouse_report(tty, sel_mode & 15, xs, ys);
 146               return 0;
 147           }
 148         }
 149 
 150         if (ps > pe)    /* make sel_start <= sel_end */
 151         {
 152                 int tmp = ps;
 153                 ps = pe;
 154                 pe = tmp;
 155         }
 156 
 157         if (sel_cons != fg_console) {
 158                 clear_selection();
 159                 sel_cons = fg_console;
 160         }
 161 
 162         switch (sel_mode)
 163         {
 164                 case 0: /* character-by-character selection */
 165                         new_sel_start = ps;
 166                         new_sel_end = pe;
 167                         break;
 168                 case 1: /* word-by-word selection */
 169                         spc = isspace(sel_pos(ps));
 170                         for (new_sel_start = ps; ; ps -= 2)
 171                         {
 172                                 if ((spc && !isspace(sel_pos(ps))) ||
 173                                     (!spc && !inword(sel_pos(ps))))
 174                                         break;
 175                                 new_sel_start = ps;
 176                                 if (!(ps % video_size_row))
 177                                         break;
 178                         }
 179                         spc = isspace(sel_pos(pe));
 180                         for (new_sel_end = pe; ; pe += 2)
 181                         {
 182                                 if ((spc && !isspace(sel_pos(pe))) ||
 183                                     (!spc && !inword(sel_pos(pe))))
 184                                         break;
 185                                 new_sel_end = pe;
 186                                 if (!((pe + 2) % video_size_row))
 187                                         break;
 188                         }
 189                         break;
 190                 case 2: /* line-by-line selection */
 191                         new_sel_start = ps - ps % video_size_row;
 192                         new_sel_end = pe + video_size_row
 193                                     - pe % video_size_row - 2;
 194                         break;
 195                 case 3:
 196                         highlight_pointer(pe);
 197                         return 0;
 198                 default:
 199                         return -EINVAL;
 200         }
 201 
 202         /* remove the pointer */
 203         highlight_pointer(-1);
 204 
 205         /* select to end of line if on trailing space */
 206         if (new_sel_end > new_sel_start &&
 207                 !atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
 208                 for (pe = new_sel_end + 2; ; pe += 2)
 209                         if (!isspace(sel_pos(pe)) || atedge(pe))
 210                                 break;
 211                 if (isspace(sel_pos(pe)))
 212                         new_sel_end = pe;
 213         }
 214         if (sel_start == -1)    /* no current selection */
 215                 highlight(new_sel_start, new_sel_end);
 216         else if (new_sel_start == sel_start)
 217         {
 218                 if (new_sel_end == sel_end)     /* no action required */
 219                         return 0;
 220                 else if (new_sel_end > sel_end) /* extend to right */
 221                         highlight(sel_end + 2, new_sel_end);
 222                 else                            /* contract from right */
 223                         highlight(new_sel_end + 2, sel_end);
 224         }
 225         else if (new_sel_end == sel_end)
 226         {
 227                 if (new_sel_start < sel_start)  /* extend to left */
 228                         highlight(new_sel_start, sel_start - 2);
 229                 else                            /* contract from left */
 230                         highlight(sel_start, new_sel_start - 2);
 231         }
 232         else    /* some other case; start selection from scratch */
 233         {
 234                 clear_selection();
 235                 highlight(new_sel_start, new_sel_end);
 236         }
 237         sel_start = new_sel_start;
 238         sel_end = new_sel_end;
 239 
 240         if (sel_buffer)
 241                 kfree(sel_buffer);
 242         sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
 243         if (!sel_buffer) {
 244                 printk("selection: kmalloc() failed\n");
 245                 clear_selection();
 246                 return -ENOMEM;
 247         }
 248 
 249         obp = bp = sel_buffer;
 250         for (i = sel_start; i <= sel_end; i += 2) {
 251                 *bp = sel_pos(i);
 252                 if (!isspace(*bp++))
 253                         obp = bp;
 254                 if (! ((i + 2) % video_size_row)) {
 255                         /* strip trailing blanks from line and add newline,
 256                            unless non-space at end of line. */
 257                         if (obp != bp) {
 258                                 bp = obp;
 259                                 *bp++ = '\r';
 260                         }
 261                         obp = bp;
 262                 }
 263         }
 264         sel_buffer_lth = bp - sel_buffer;
 265         return 0;
 266 }
 267 
 268 /* Insert the contents of the selection buffer into the queue of the
 269    tty associated with the current console. Invoked by ioctl(). */
 270 int paste_selection(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272         struct wait_queue wait = { current, NULL };
 273         char    *bp = sel_buffer;
 274         int     c = sel_buffer_lth;
 275         int     l;
 276         struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
 277         
 278         if (!bp || !c)
 279                 return 0;
 280         do_unblank_screen();
 281         current->state = TASK_INTERRUPTIBLE;
 282         add_wait_queue(&vt->paste_wait, &wait);
 283         while (c) {
 284                 if (test_bit(TTY_THROTTLED, &tty->flags)) {
 285                         schedule();
 286                         continue;
 287                 }
 288                 l = MIN(c, tty->ldisc.receive_room(tty));
 289                 tty->ldisc.receive_buf(tty, bp, 0, l);
 290                 c -= l;
 291                 bp += l;
 292         }
 293         current->state = TASK_RUNNING;
 294         return 0;
 295 }

/* [previous][next][first][last][top][bottom][index][help] */