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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [selection.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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/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/vt_kern.h>
24
#include <linux/consolemap.h>
25
#include <linux/console_struct.h>
26
#include <linux/selection.h>
27
 
28
#ifndef MIN
29
#define MIN(a,b)        ((a) < (b) ? (a) : (b))
30
#endif
31
 
32
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
33
#define isspace(c)      ((c) == ' ')
34
 
35
extern void poke_blanked_console(void);
36
 
37
/* Variables for selection control. */
38
/* Use a dynamic buffer, instead of static (Dec 1994) */
39
       int sel_cons;            /* must not be disallocated */
40
static volatile int sel_start = -1;     /* cleared by clear_selection */
41
static int sel_end;
42
static int sel_buffer_lth;
43
static char *sel_buffer;
44
 
45
/* clear_selection, highlight and highlight_pointer can be called
46
   from interrupt (via scrollback/front) */
47
 
48
/* set reverse video on characters s-e of console with selection. */
49
inline static void
50
highlight(const int s, const int e) {
51
        invert_screen(sel_cons, s, e-s+2, 1);
52
}
53
 
54
/* use complementary color to show the pointer */
55
inline static void
56
highlight_pointer(const int where) {
57
        complement_pos(sel_cons, where);
58
}
59
 
60
static unsigned char
61
sel_pos(int n)
62
{
63
        return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n));
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 unsigned char c) {
93
        return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
94
}
95
 
96
/* set inwordLut contents. Invoked by ioctl(). */
97
int sel_loadlut(const unsigned long arg)
98
{
99
        return copy_from_user(inwordLut, (u32 *)(arg+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
/* set the current selection. Invoked by ioctl() or by kernel code. */
115
int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
116
{
117
        int sel_mode, new_sel_start, new_sel_end, spc;
118
        char *bp, *obp;
119
        int i, ps, pe;
120
        unsigned int currcons = fg_console;
121
 
122
        unblank_screen();
123
        poke_blanked_console();
124
 
125
        { unsigned short *args, xs, ys, xe, ye;
126
 
127
          args = (unsigned short *)(arg + 1);
128
          if (user) {
129
                  if (verify_area(VERIFY_READ, args, sizeof(short) * 5))
130
                        return -EFAULT;
131
                  __get_user(xs, args++);
132
                  __get_user(ys, args++);
133
                  __get_user(xe, args++);
134
                  __get_user(ye, args++);
135
                  __get_user(sel_mode, args);
136
          } else {
137
                  xs = *(args++); /* set selection from kernel */
138
                  ys = *(args++);
139
                  xe = *(args++);
140
                  ye = *(args++);
141
                  sel_mode = *args;
142
          }
143
          xs--; ys--; xe--; ye--;
144
          xs = limit(xs, video_num_columns - 1);
145
          ys = limit(ys, video_num_lines - 1);
146
          xe = limit(xe, video_num_columns - 1);
147
          ye = limit(ye, video_num_lines - 1);
148
          ps = ys * video_size_row + (xs << 1);
149
          pe = ye * video_size_row + (xe << 1);
150
 
151
          if (sel_mode == 4) {
152
              /* useful for screendump without selection highlights */
153
              clear_selection();
154
              return 0;
155
          }
156
 
157
          if (mouse_reporting() && (sel_mode & 16)) {
158
              mouse_report(tty, sel_mode & 15, xs, ys);
159
              return 0;
160
          }
161
        }
162
 
163
        if (ps > pe)    /* make sel_start <= sel_end */
164
        {
165
                int tmp = ps;
166
                ps = pe;
167
                pe = tmp;
168
        }
169
 
170
        if (sel_cons != fg_console) {
171
                clear_selection();
172
                sel_cons = fg_console;
173
        }
174
 
175
        switch (sel_mode)
176
        {
177
                case 0:  /* character-by-character selection */
178
                        new_sel_start = ps;
179
                        new_sel_end = pe;
180
                        break;
181
                case 1: /* word-by-word selection */
182
                        spc = isspace(sel_pos(ps));
183
                        for (new_sel_start = ps; ; ps -= 2)
184
                        {
185
                                if ((spc && !isspace(sel_pos(ps))) ||
186
                                    (!spc && !inword(sel_pos(ps))))
187
                                        break;
188
                                new_sel_start = ps;
189
                                if (!(ps % video_size_row))
190
                                        break;
191
                        }
192
                        spc = isspace(sel_pos(pe));
193
                        for (new_sel_end = pe; ; pe += 2)
194
                        {
195
                                if ((spc && !isspace(sel_pos(pe))) ||
196
                                    (!spc && !inword(sel_pos(pe))))
197
                                        break;
198
                                new_sel_end = pe;
199
                                if (!((pe + 2) % video_size_row))
200
                                        break;
201
                        }
202
                        break;
203
                case 2: /* line-by-line selection */
204
                        new_sel_start = ps - ps % video_size_row;
205
                        new_sel_end = pe + video_size_row
206
                                    - pe % video_size_row - 2;
207
                        break;
208
                case 3:
209
                        highlight_pointer(pe);
210
                        return 0;
211
                default:
212
                        return -EINVAL;
213
        }
214
 
215
        /* remove the pointer */
216
        highlight_pointer(-1);
217
 
218
        /* select to end of line if on trailing space */
219
        if (new_sel_end > new_sel_start &&
220
                !atedge(new_sel_end, video_size_row) &&
221
                isspace(sel_pos(new_sel_end))) {
222
                for (pe = new_sel_end + 2; ; pe += 2)
223
                        if (!isspace(sel_pos(pe)) ||
224
                            atedge(pe, video_size_row))
225
                                break;
226
                if (isspace(sel_pos(pe)))
227
                        new_sel_end = pe;
228
        }
229
        if (sel_start == -1)    /* no current selection */
230
                highlight(new_sel_start, new_sel_end);
231
        else if (new_sel_start == sel_start)
232
        {
233
                if (new_sel_end == sel_end)     /* no action required */
234
                        return 0;
235
                else if (new_sel_end > sel_end) /* extend to right */
236
                        highlight(sel_end + 2, new_sel_end);
237
                else                            /* contract from right */
238
                        highlight(new_sel_end + 2, sel_end);
239
        }
240
        else if (new_sel_end == sel_end)
241
        {
242
                if (new_sel_start < sel_start)  /* extend to left */
243
                        highlight(new_sel_start, sel_start - 2);
244
                else                            /* contract from left */
245
                        highlight(sel_start, new_sel_start - 2);
246
        }
247
        else    /* some other case; start selection from scratch */
248
        {
249
                clear_selection();
250
                highlight(new_sel_start, new_sel_end);
251
        }
252
        sel_start = new_sel_start;
253
        sel_end = new_sel_end;
254
 
255
        /* Allocate a new buffer before freeing the old one ... */
256
        bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
257
        if (!bp) {
258
                printk(KERN_WARNING "selection: kmalloc() failed\n");
259
                clear_selection();
260
                return -ENOMEM;
261
        }
262
        if (sel_buffer)
263
                kfree(sel_buffer);
264
        sel_buffer = bp;
265
 
266
        obp = bp;
267
        for (i = sel_start; i <= sel_end; i += 2) {
268
                *bp = sel_pos(i);
269
                if (!isspace(*bp++))
270
                        obp = bp;
271
                if (! ((i + 2) % video_size_row)) {
272
                        /* strip trailing blanks from line and add newline,
273
                           unless non-space at end of line. */
274
                        if (obp != bp) {
275
                                bp = obp;
276
                                *bp++ = '\r';
277
                        }
278
                        obp = bp;
279
                }
280
        }
281
        sel_buffer_lth = bp - sel_buffer;
282
        return 0;
283
}
284
 
285
/* Insert the contents of the selection buffer into the
286
 * queue of the tty associated with the current console.
287
 * Invoked by ioctl().
288
 */
289
int paste_selection(struct tty_struct *tty)
290
{
291
        struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
292
        int     pasted = 0, count;
293
        DECLARE_WAITQUEUE(wait, current);
294
 
295
        poke_blanked_console();
296
        add_wait_queue(&vt->paste_wait, &wait);
297
        while (sel_buffer && sel_buffer_lth > pasted) {
298
                set_current_state(TASK_INTERRUPTIBLE);
299
                if (test_bit(TTY_THROTTLED, &tty->flags)) {
300
                        schedule();
301
                        continue;
302
                }
303
                count = sel_buffer_lth - pasted;
304
                count = MIN(count, tty->ldisc.receive_room(tty));
305
                tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
306
                pasted += count;
307
        }
308
        remove_wait_queue(&vt->paste_wait, &wait);
309
        current->state = TASK_RUNNING;
310
        return 0;
311
}
312
 
313
EXPORT_SYMBOL(set_selection);
314
EXPORT_SYMBOL(paste_selection);

powered by: WebSVN 2.1.0

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