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() or by kernel code. */
 114 int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
     /* [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           if (user) {
 126                   xs = get_user(args++) - 1;
 127                   ys = get_user(args++) - 1;
 128                   xe = get_user(args++) - 1;
 129                   ye = get_user(args++) - 1;
 130                   sel_mode = get_user(args);
 131           } else {
 132                   xs = *(args++) - 1; /* set selection from kernel */
 133                   ys = *(args++) - 1;
 134                   xe = *(args++) - 1;
 135                   ye = *(args++) - 1;
 136                   sel_mode = *args;
 137           }
 138           xs = limit(xs, video_num_columns - 1);
 139           ys = limit(ys, video_num_lines - 1);
 140           xe = limit(xe, video_num_columns - 1);
 141           ye = limit(ye, video_num_lines - 1);
 142           ps = ys * video_size_row + (xs << 1);
 143           pe = ye * video_size_row + (xe << 1);
 144 
 145           if (sel_mode == 4) {
 146               /* useful for screendump without selection highlights */
 147               clear_selection();
 148               return 0;
 149           }
 150 
 151           if (mouse_reporting() && (sel_mode & 16)) {
 152               mouse_report(tty, sel_mode & 15, xs, ys);
 153               return 0;
 154           }
 155         }
 156 
 157         if (ps > pe)    /* make sel_start <= sel_end */
 158         {
 159                 int tmp = ps;
 160                 ps = pe;
 161                 pe = tmp;
 162         }
 163 
 164         if (sel_cons != fg_console) {
 165                 clear_selection();
 166                 sel_cons = fg_console;
 167         }
 168 
 169         switch (sel_mode)
 170         {
 171                 case 0: /* character-by-character selection */
 172                         new_sel_start = ps;
 173                         new_sel_end = pe;
 174                         break;
 175                 case 1: /* word-by-word selection */
 176                         spc = isspace(sel_pos(ps));
 177                         for (new_sel_start = ps; ; ps -= 2)
 178                         {
 179                                 if ((spc && !isspace(sel_pos(ps))) ||
 180                                     (!spc && !inword(sel_pos(ps))))
 181                                         break;
 182                                 new_sel_start = ps;
 183                                 if (!(ps % video_size_row))
 184                                         break;
 185                         }
 186                         spc = isspace(sel_pos(pe));
 187                         for (new_sel_end = pe; ; pe += 2)
 188                         {
 189                                 if ((spc && !isspace(sel_pos(pe))) ||
 190                                     (!spc && !inword(sel_pos(pe))))
 191                                         break;
 192                                 new_sel_end = pe;
 193                                 if (!((pe + 2) % video_size_row))
 194                                         break;
 195                         }
 196                         break;
 197                 case 2: /* line-by-line selection */
 198                         new_sel_start = ps - ps % video_size_row;
 199                         new_sel_end = pe + video_size_row
 200                                     - pe % video_size_row - 2;
 201                         break;
 202                 case 3:
 203                         highlight_pointer(pe);
 204                         return 0;
 205                 default:
 206                         return -EINVAL;
 207         }
 208 
 209         /* remove the pointer */
 210         highlight_pointer(-1);
 211 
 212         /* select to end of line if on trailing space */
 213         if (new_sel_end > new_sel_start &&
 214                 !atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
 215                 for (pe = new_sel_end + 2; ; pe += 2)
 216                         if (!isspace(sel_pos(pe)) || atedge(pe))
 217                                 break;
 218                 if (isspace(sel_pos(pe)))
 219                         new_sel_end = pe;
 220         }
 221         if (sel_start == -1)    /* no current selection */
 222                 highlight(new_sel_start, new_sel_end);
 223         else if (new_sel_start == sel_start)
 224         {
 225                 if (new_sel_end == sel_end)     /* no action required */
 226                         return 0;
 227                 else if (new_sel_end > sel_end) /* extend to right */
 228                         highlight(sel_end + 2, new_sel_end);
 229                 else                            /* contract from right */
 230                         highlight(new_sel_end + 2, sel_end);
 231         }
 232         else if (new_sel_end == sel_end)
 233         {
 234                 if (new_sel_start < sel_start)  /* extend to left */
 235                         highlight(new_sel_start, sel_start - 2);
 236                 else                            /* contract from left */
 237                         highlight(sel_start, new_sel_start - 2);
 238         }
 239         else    /* some other case; start selection from scratch */
 240         {
 241                 clear_selection();
 242                 highlight(new_sel_start, new_sel_end);
 243         }
 244         sel_start = new_sel_start;
 245         sel_end = new_sel_end;
 246 
 247         if (sel_buffer)
 248                 kfree(sel_buffer);
 249         sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
 250         if (!sel_buffer) {
 251                 printk("selection: kmalloc() failed\n");
 252                 clear_selection();
 253                 return -ENOMEM;
 254         }
 255 
 256         obp = bp = sel_buffer;
 257         for (i = sel_start; i <= sel_end; i += 2) {
 258                 *bp = sel_pos(i);
 259                 if (!isspace(*bp++))
 260                         obp = bp;
 261                 if (! ((i + 2) % video_size_row)) {
 262                         /* strip trailing blanks from line and add newline,
 263                            unless non-space at end of line. */
 264                         if (obp != bp) {
 265                                 bp = obp;
 266                                 *bp++ = '\r';
 267                         }
 268                         obp = bp;
 269                 }
 270         }
 271         sel_buffer_lth = bp - sel_buffer;
 272         return 0;
 273 }
 274 
 275 /* Insert the contents of the selection buffer into the queue of the
 276    tty associated with the current console. Invoked by ioctl(). */
 277 int paste_selection(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279         struct wait_queue wait = { current, NULL };
 280         char    *bp = sel_buffer;
 281         int     c = sel_buffer_lth;
 282         int     l;
 283         struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
 284         
 285         if (!bp || !c)
 286                 return 0;
 287         do_unblank_screen();
 288         current->state = TASK_INTERRUPTIBLE;
 289         add_wait_queue(&vt->paste_wait, &wait);
 290         while (c) {
 291                 if (test_bit(TTY_THROTTLED, &tty->flags)) {
 292                         schedule();
 293                         continue;
 294                 }
 295                 l = MIN(c, tty->ldisc.receive_room(tty));
 296                 tty->ldisc.receive_buf(tty, bp, 0, l);
 297                 c -= l;
 298                 bp += l;
 299         }
 300         current->state = TASK_RUNNING;
 301         return 0;
 302 }

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