home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / char / selection.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  7.3 KB  |  295 lines

  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) {
  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) {
  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) {
  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) {
  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)
  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)
  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)
  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)
  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)
  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. }
  295.