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

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