OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [selection.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/drivers/char/selection.c
3
 *
4
 * This module exports the functions:
5
 *
6
 *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
7
 *     'void clear_selection(void)'
8
 *     'int paste_selection(struct tty_struct *)'
9
 *     'int sel_loadlut(char __user *)'
10
 *
11
 * Now that /dev/vcs exists, most of this can disappear again.
12
 */
13
 
14
#include <linux/module.h>
15
#include <linux/tty.h>
16
#include <linux/sched.h>
17
#include <linux/mm.h>
18
#include <linux/slab.h>
19
#include <linux/types.h>
20
 
21
#include <asm/uaccess.h>
22
 
23
#include <linux/kbd_kern.h>
24
#include <linux/vt_kern.h>
25
#include <linux/consolemap.h>
26
#include <linux/selection.h>
27
#include <linux/tiocl.h>
28
#include <linux/console.h>
29
 
30
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
31
#define isspace(c)      ((c) == ' ')
32
 
33
extern void poke_blanked_console(void);
34
 
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
/* remove the current selection highlight, if any,
67
   from the console holding the selection. */
68
void
69
clear_selection(void) {
70
        highlight_pointer(-1); /* hide the pointer */
71
        if (sel_start != -1) {
72
                highlight(sel_start, sel_end);
73
                sel_start = -1;
74
        }
75
}
76
 
77
/*
78
 * User settable table: what characters are to be considered alphabetic?
79
 * 256 bits
80
 */
81
static u32 inwordLut[8]={
82
  0x00000000, /* control chars     */
83
  0x03FF0000, /* digits            */
84
  0x87FFFFFE, /* uppercase and '_' */
85
  0x07FFFFFE, /* lowercase         */
86
  0x00000000,
87
  0x00000000,
88
  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
89
  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
90
};
91
 
92
static inline int inword(const u16 c) {
93
        return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
94
}
95
 
96
/* set inwordLut contents. Invoked by ioctl(). */
97
int sel_loadlut(char __user *p)
98
{
99
        return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
100
}
101
 
102
/* does screen address p correspond to character at LH/RH edge of screen? */
103
static inline int atedge(const int p, int size_row)
104
{
105
        return (!(p % size_row) || !((p + 2) % size_row));
106
}
107
 
108
/* constrain v such that v <= u */
109
static inline unsigned short limit(const unsigned short v, const unsigned short u)
110
{
111
        return (v > u) ? u : v;
112
}
113
 
114
/* stores the char in UTF8 and returns the number of bytes used (1-3) */
115
static int store_utf8(u16 c, char *p)
116
{
117
        if (c < 0x80) {
118
                /*  0******* */
119
                p[0] = c;
120
                return 1;
121
        } else if (c < 0x800) {
122
                /* 110***** 10****** */
123
                p[0] = 0xc0 | (c >> 6);
124
                p[1] = 0x80 | (c & 0x3f);
125
                return 2;
126
        } else {
127
                /* 1110**** 10****** 10****** */
128
                p[0] = 0xe0 | (c >> 12);
129
                p[1] = 0x80 | ((c >> 6) & 0x3f);
130
                p[2] = 0x80 | (c & 0x3f);
131
                return 3;
132
        }
133
}
134
 
135
/* set the current selection. Invoked by ioctl() or by kernel code. */
136
int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
137
{
138
        struct vc_data *vc = vc_cons[fg_console].d;
139
        int sel_mode, new_sel_start, new_sel_end, spc;
140
        char *bp, *obp;
141
        int i, ps, pe, multiplier;
142
        u16 c;
143
        struct kbd_struct *kbd = kbd_table + fg_console;
144
 
145
        poke_blanked_console();
146
 
147
        { unsigned short xs, ys, xe, ye;
148
 
149
          if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
150
                return -EFAULT;
151
          __get_user(xs, &sel->xs);
152
          __get_user(ys, &sel->ys);
153
          __get_user(xe, &sel->xe);
154
          __get_user(ye, &sel->ye);
155
          __get_user(sel_mode, &sel->sel_mode);
156
          xs--; ys--; xe--; ye--;
157
          xs = limit(xs, vc->vc_cols - 1);
158
          ys = limit(ys, vc->vc_rows - 1);
159
          xe = limit(xe, vc->vc_cols - 1);
160
          ye = limit(ye, vc->vc_rows - 1);
161
          ps = ys * vc->vc_size_row + (xs << 1);
162
          pe = ye * vc->vc_size_row + (xe << 1);
163
 
164
          if (sel_mode == TIOCL_SELCLEAR) {
165
              /* useful for screendump without selection highlights */
166
              clear_selection();
167
              return 0;
168
          }
169
 
170
          if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
171
              mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
172
              return 0;
173
          }
174
        }
175
 
176
        if (ps > pe)    /* make sel_start <= sel_end */
177
        {
178
                int tmp = ps;
179
                ps = pe;
180
                pe = tmp;
181
        }
182
 
183
        if (sel_cons != vc_cons[fg_console].d) {
184
                clear_selection();
185
                sel_cons = vc_cons[fg_console].d;
186
        }
187
        use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
188
 
189
        switch (sel_mode)
190
        {
191
                case TIOCL_SELCHAR:     /* character-by-character selection */
192
                        new_sel_start = ps;
193
                        new_sel_end = pe;
194
                        break;
195
                case TIOCL_SELWORD:     /* word-by-word selection */
196
                        spc = isspace(sel_pos(ps));
197
                        for (new_sel_start = ps; ; ps -= 2)
198
                        {
199
                                if ((spc && !isspace(sel_pos(ps))) ||
200
                                    (!spc && !inword(sel_pos(ps))))
201
                                        break;
202
                                new_sel_start = ps;
203
                                if (!(ps % vc->vc_size_row))
204
                                        break;
205
                        }
206
                        spc = isspace(sel_pos(pe));
207
                        for (new_sel_end = pe; ; pe += 2)
208
                        {
209
                                if ((spc && !isspace(sel_pos(pe))) ||
210
                                    (!spc && !inword(sel_pos(pe))))
211
                                        break;
212
                                new_sel_end = pe;
213
                                if (!((pe + 2) % vc->vc_size_row))
214
                                        break;
215
                        }
216
                        break;
217
                case TIOCL_SELLINE:     /* line-by-line selection */
218
                        new_sel_start = ps - ps % vc->vc_size_row;
219
                        new_sel_end = pe + vc->vc_size_row
220
                                    - pe % vc->vc_size_row - 2;
221
                        break;
222
                case TIOCL_SELPOINTER:
223
                        highlight_pointer(pe);
224
                        return 0;
225
                default:
226
                        return -EINVAL;
227
        }
228
 
229
        /* remove the pointer */
230
        highlight_pointer(-1);
231
 
232
        /* select to end of line if on trailing space */
233
        if (new_sel_end > new_sel_start &&
234
                !atedge(new_sel_end, vc->vc_size_row) &&
235
                isspace(sel_pos(new_sel_end))) {
236
                for (pe = new_sel_end + 2; ; pe += 2)
237
                        if (!isspace(sel_pos(pe)) ||
238
                            atedge(pe, vc->vc_size_row))
239
                                break;
240
                if (isspace(sel_pos(pe)))
241
                        new_sel_end = pe;
242
        }
243
        if (sel_start == -1)    /* no current selection */
244
                highlight(new_sel_start, new_sel_end);
245
        else if (new_sel_start == sel_start)
246
        {
247
                if (new_sel_end == sel_end)     /* no action required */
248
                        return 0;
249
                else if (new_sel_end > sel_end) /* extend to right */
250
                        highlight(sel_end + 2, new_sel_end);
251
                else                            /* contract from right */
252
                        highlight(new_sel_end + 2, sel_end);
253
        }
254
        else if (new_sel_end == sel_end)
255
        {
256
                if (new_sel_start < sel_start)  /* extend to left */
257
                        highlight(new_sel_start, sel_start - 2);
258
                else                            /* contract from left */
259
                        highlight(sel_start, new_sel_start - 2);
260
        }
261
        else    /* some other case; start selection from scratch */
262
        {
263
                clear_selection();
264
                highlight(new_sel_start, new_sel_end);
265
        }
266
        sel_start = new_sel_start;
267
        sel_end = new_sel_end;
268
 
269
        /* Allocate a new buffer before freeing the old one ... */
270
        multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
271
        bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);
272
        if (!bp) {
273
                printk(KERN_WARNING "selection: kmalloc() failed\n");
274
                clear_selection();
275
                return -ENOMEM;
276
        }
277
        kfree(sel_buffer);
278
        sel_buffer = bp;
279
 
280
        obp = bp;
281
        for (i = sel_start; i <= sel_end; i += 2) {
282
                c = sel_pos(i);
283
                if (use_unicode)
284
                        bp += store_utf8(c, bp);
285
                else
286
                        *bp++ = c;
287
                if (!isspace(c))
288
                        obp = bp;
289
                if (! ((i + 2) % vc->vc_size_row)) {
290
                        /* strip trailing blanks from line and add newline,
291
                           unless non-space at end of line. */
292
                        if (obp != bp) {
293
                                bp = obp;
294
                                *bp++ = '\r';
295
                        }
296
                        obp = bp;
297
                }
298
        }
299
        sel_buffer_lth = bp - sel_buffer;
300
        return 0;
301
}
302
 
303
/* Insert the contents of the selection buffer into the
304
 * queue of the tty associated with the current console.
305
 * Invoked by ioctl().
306
 */
307
int paste_selection(struct tty_struct *tty)
308
{
309
        struct vc_data *vc = (struct vc_data *)tty->driver_data;
310
        int     pasted = 0;
311
        unsigned int count;
312
        struct  tty_ldisc *ld;
313
        DECLARE_WAITQUEUE(wait, current);
314
 
315
        acquire_console_sem();
316
        poke_blanked_console();
317
        release_console_sem();
318
 
319
        ld = tty_ldisc_ref_wait(tty);
320
 
321
        add_wait_queue(&vc->paste_wait, &wait);
322
        while (sel_buffer && sel_buffer_lth > pasted) {
323
                set_current_state(TASK_INTERRUPTIBLE);
324
                if (test_bit(TTY_THROTTLED, &tty->flags)) {
325
                        schedule();
326
                        continue;
327
                }
328
                count = sel_buffer_lth - pasted;
329
                count = min(count, tty->receive_room);
330
                tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count);
331
                pasted += count;
332
        }
333
        remove_wait_queue(&vc->paste_wait, &wait);
334
        __set_current_state(TASK_RUNNING);
335
 
336
        tty_ldisc_deref(ld);
337
        return 0;
338
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.