Line data Source code
1 : /* $OpenBSD: tty_subr.c,v 1.33 2016/03/14 23:08:06 krw Exp $ */
2 : /* $NetBSD: tty_subr.c,v 1.13 1996/02/09 19:00:43 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1993, 1994 Theo de Raadt
6 : * All rights reserved.
7 : *
8 : * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
9 : * set of true clist functions that this is very loosely based on.
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : * 1. Redistributions of source code must retain the above copyright
15 : * notice, this list of conditions and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : */
31 :
32 : #include <sys/param.h>
33 : #include <sys/systm.h>
34 : #include <sys/ioctl.h>
35 : #include <sys/tty.h>
36 : #include <sys/malloc.h>
37 :
38 : /*
39 : * If TTY_QUOTE functionality isn't required by a line discipline,
40 : * it can free c_cq and set it to NULL. This speeds things up,
41 : * and also does not use any extra memory. This is useful for (say)
42 : * a SLIP line discipline that wants a 32K ring buffer for data
43 : * but doesn't need quoting.
44 : */
45 : #define QMEM(n) ((((n)-1)/NBBY)+1)
46 :
47 : void clrbits(u_char *, int, int);
48 :
49 : /*
50 : * Initialize a particular clist. Ok, they are really ring buffers,
51 : * of the specified length, with/without quoting support.
52 : */
53 : void
54 0 : clalloc(struct clist *clp, int size, int quot)
55 : {
56 :
57 0 : clp->c_cs = malloc(size, M_TTYS, M_WAITOK|M_ZERO);
58 :
59 0 : if (quot)
60 0 : clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK|M_ZERO);
61 : else
62 0 : clp->c_cq = NULL;
63 :
64 0 : clp->c_cf = clp->c_cl = NULL;
65 0 : clp->c_ce = clp->c_cs + size;
66 0 : clp->c_cn = size;
67 0 : clp->c_cc = 0;
68 0 : }
69 :
70 : void
71 0 : clfree(struct clist *clp)
72 : {
73 0 : if (clp->c_cs) {
74 0 : explicit_bzero(clp->c_cs, clp->c_cn);
75 0 : free(clp->c_cs, M_TTYS, clp->c_cn);
76 0 : }
77 0 : if (clp->c_cq) {
78 0 : explicit_bzero(clp->c_cq, QMEM(clp->c_cn));
79 0 : free(clp->c_cq, M_TTYS, QMEM(clp->c_cn));
80 0 : }
81 0 : clp->c_cs = clp->c_cq = NULL;
82 0 : }
83 :
84 :
85 : /*
86 : * Get a character from a clist.
87 : */
88 : int
89 0 : getc(struct clist *clp)
90 : {
91 : int c = -1;
92 : int s;
93 :
94 0 : s = spltty();
95 0 : if (clp->c_cc == 0)
96 : goto out;
97 :
98 0 : c = *clp->c_cf & 0xff;
99 0 : *clp->c_cf = 0;
100 0 : if (clp->c_cq) {
101 0 : if (isset(clp->c_cq, clp->c_cf - clp->c_cs))
102 0 : c |= TTY_QUOTE;
103 0 : clrbit(clp->c_cq, clp->c_cf - clp->c_cs);
104 0 : }
105 0 : if (++clp->c_cf == clp->c_ce)
106 0 : clp->c_cf = clp->c_cs;
107 0 : if (--clp->c_cc == 0)
108 0 : clp->c_cf = clp->c_cl = NULL;
109 : out:
110 0 : splx(s);
111 0 : return c;
112 : }
113 :
114 : /*
115 : * Copy clist to buffer.
116 : * Return number of bytes moved.
117 : */
118 : int
119 0 : q_to_b(struct clist *clp, u_char *cp, int count)
120 : {
121 : int cc;
122 : u_char *p = cp;
123 : int s;
124 :
125 0 : s = spltty();
126 : /* optimize this while loop */
127 0 : while (count > 0 && clp->c_cc > 0) {
128 0 : cc = clp->c_cl - clp->c_cf;
129 0 : if (clp->c_cf >= clp->c_cl)
130 0 : cc = clp->c_ce - clp->c_cf;
131 0 : if (cc > count)
132 0 : cc = count;
133 0 : memcpy(p, clp->c_cf, cc);
134 0 : memset(clp->c_cf, 0, cc);
135 0 : if (clp->c_cq)
136 0 : clrbits(clp->c_cq, clp->c_cf - clp->c_cs, cc);
137 0 : count -= cc;
138 0 : p += cc;
139 0 : clp->c_cc -= cc;
140 0 : clp->c_cf += cc;
141 0 : if (clp->c_cf == clp->c_ce)
142 0 : clp->c_cf = clp->c_cs;
143 : }
144 0 : if (clp->c_cc == 0)
145 0 : clp->c_cf = clp->c_cl = NULL;
146 0 : splx(s);
147 0 : return p - cp;
148 : }
149 :
150 : /*
151 : * Return count of contiguous characters in clist.
152 : * Stop counting if flag&character is non-null.
153 : */
154 : int
155 0 : ndqb(struct clist *clp, int flag)
156 : {
157 : int count = 0;
158 : int i;
159 : int cc;
160 : int s;
161 :
162 0 : s = spltty();
163 0 : if ((cc = clp->c_cc) == 0)
164 : goto out;
165 :
166 0 : if (flag == 0) {
167 0 : count = clp->c_cl - clp->c_cf;
168 0 : if (count <= 0)
169 0 : count = clp->c_ce - clp->c_cf;
170 : goto out;
171 : }
172 :
173 0 : i = clp->c_cf - clp->c_cs;
174 0 : if (flag & TTY_QUOTE) {
175 0 : while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
176 0 : isset(clp->c_cq, i))) {
177 0 : count++;
178 0 : if (i == clp->c_cn)
179 : break;
180 : }
181 : } else {
182 0 : while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
183 0 : count++;
184 0 : if (i == clp->c_cn)
185 : break;
186 : }
187 : }
188 : out:
189 0 : splx(s);
190 0 : return count;
191 : }
192 :
193 : /*
194 : * Flush count bytes from clist.
195 : */
196 : void
197 0 : ndflush(struct clist *clp, int count)
198 : {
199 : int cc;
200 : int s;
201 :
202 0 : s = spltty();
203 0 : if (count == clp->c_cc) {
204 0 : clp->c_cc = 0;
205 0 : clp->c_cf = clp->c_cl = NULL;
206 0 : goto out;
207 : }
208 : /* optimize this while loop */
209 0 : while (count > 0 && clp->c_cc > 0) {
210 0 : cc = clp->c_cl - clp->c_cf;
211 0 : if (clp->c_cf >= clp->c_cl)
212 0 : cc = clp->c_ce - clp->c_cf;
213 0 : if (cc > count)
214 0 : cc = count;
215 0 : count -= cc;
216 0 : clp->c_cc -= cc;
217 0 : clp->c_cf += cc;
218 0 : if (clp->c_cf == clp->c_ce)
219 0 : clp->c_cf = clp->c_cs;
220 : }
221 0 : if (clp->c_cc == 0)
222 0 : clp->c_cf = clp->c_cl = NULL;
223 : out:
224 0 : splx(s);
225 0 : }
226 :
227 : /*
228 : * Put a character into the output queue.
229 : */
230 : int
231 0 : putc(int c, struct clist *clp)
232 : {
233 : int i;
234 : int s;
235 :
236 0 : s = spltty();
237 0 : if (clp->c_cc == clp->c_cn) {
238 0 : splx(s);
239 0 : return -1;
240 : }
241 :
242 0 : if (clp->c_cc == 0) {
243 0 : if (!clp->c_cs) {
244 : #if defined(DIAGNOSTIC)
245 0 : printf("putc: required clalloc\n");
246 : #endif
247 0 : clalloc(clp, 1024, 1);
248 0 : }
249 0 : clp->c_cf = clp->c_cl = clp->c_cs;
250 0 : }
251 :
252 0 : *clp->c_cl = c & 0xff;
253 0 : i = clp->c_cl - clp->c_cs;
254 0 : if (clp->c_cq) {
255 0 : if (c & TTY_QUOTE)
256 0 : setbit(clp->c_cq, i);
257 : else
258 0 : clrbit(clp->c_cq, i);
259 : }
260 0 : clp->c_cc++;
261 0 : clp->c_cl++;
262 0 : if (clp->c_cl == clp->c_ce)
263 0 : clp->c_cl = clp->c_cs;
264 0 : splx(s);
265 0 : return 0;
266 0 : }
267 :
268 : /*
269 : * optimized version of
270 : *
271 : * for (i = 0; i < len; i++)
272 : * clrbit(cp, off + i);
273 : */
274 : void
275 0 : clrbits(u_char *cp, int off, int len)
276 : {
277 : int sby, sbi, eby, ebi;
278 : int i;
279 : u_char mask;
280 :
281 0 : if (len==1) {
282 0 : clrbit(cp, off);
283 0 : return;
284 : }
285 :
286 0 : sby = off / NBBY;
287 0 : sbi = off % NBBY;
288 0 : eby = (off+len) / NBBY;
289 0 : ebi = (off+len) % NBBY;
290 0 : if (sby == eby) {
291 0 : mask = ((1 << (ebi - sbi)) - 1) << sbi;
292 0 : cp[sby] &= ~mask;
293 0 : } else {
294 0 : mask = (1<<sbi) - 1;
295 0 : cp[sby++] &= mask;
296 :
297 0 : for (i = sby; i < eby; i++)
298 0 : cp[i] = 0x00;
299 :
300 0 : mask = (1<<ebi) - 1;
301 0 : if (mask) /* if no mask, eby may be 1 too far */
302 0 : cp[eby] &= ~mask;
303 :
304 : }
305 0 : }
306 :
307 : /*
308 : * Copy buffer to clist.
309 : * Return number of bytes not transferred.
310 : */
311 : int
312 0 : b_to_q(u_char *cp, int count, struct clist *clp)
313 : {
314 : int cc;
315 : u_char *p = cp;
316 : int s;
317 :
318 0 : if (count <= 0)
319 0 : return 0;
320 :
321 0 : s = spltty();
322 0 : if (clp->c_cc == clp->c_cn)
323 : goto out;
324 :
325 0 : if (clp->c_cc == 0) {
326 0 : if (!clp->c_cs) {
327 : #if defined(DIAGNOSTIC)
328 0 : printf("b_to_q: required clalloc\n");
329 : #endif
330 0 : clalloc(clp, 1024, 1);
331 0 : }
332 0 : clp->c_cf = clp->c_cl = clp->c_cs;
333 0 : }
334 :
335 : /* optimize this while loop */
336 0 : while (count > 0 && clp->c_cc < clp->c_cn) {
337 0 : cc = clp->c_ce - clp->c_cl;
338 0 : if (clp->c_cf > clp->c_cl)
339 0 : cc = clp->c_cf - clp->c_cl;
340 0 : if (cc > count)
341 0 : cc = count;
342 0 : memcpy(clp->c_cl, p, cc);
343 0 : if (clp->c_cq)
344 0 : clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
345 0 : p += cc;
346 0 : count -= cc;
347 0 : clp->c_cc += cc;
348 0 : clp->c_cl += cc;
349 0 : if (clp->c_cl == clp->c_ce)
350 0 : clp->c_cl = clp->c_cs;
351 : }
352 : out:
353 0 : splx(s);
354 0 : return count;
355 0 : }
356 :
357 : static int cc;
358 :
359 : /*
360 : * Given a non-NULL pointer into the clist return the pointer
361 : * to the next character in the list or return NULL if no more chars.
362 : *
363 : * Callers must not allow getc's to happen between firstc's and nextc's
364 : * so that the pointer becomes invalid. Note that interrupts are NOT
365 : * masked.
366 : */
367 : u_char *
368 0 : nextc(struct clist *clp, u_char *cp, int *c)
369 : {
370 :
371 0 : if (clp->c_cf == cp) {
372 : /*
373 : * First time initialization.
374 : */
375 0 : cc = clp->c_cc;
376 0 : }
377 0 : if (cc == 0 || cp == NULL)
378 0 : return NULL;
379 0 : if (--cc == 0)
380 0 : return NULL;
381 0 : if (++cp == clp->c_ce)
382 0 : cp = clp->c_cs;
383 0 : *c = *cp & 0xff;
384 0 : if (clp->c_cq) {
385 0 : if (isset(clp->c_cq, cp - clp->c_cs))
386 0 : *c |= TTY_QUOTE;
387 : }
388 0 : return cp;
389 0 : }
390 :
391 : /*
392 : * Given a non-NULL pointer into the clist return the pointer
393 : * to the first character in the list or return NULL if no more chars.
394 : *
395 : * Callers must not allow getc's to happen between firstc's and nextc's
396 : * so that the pointer becomes invalid. Note that interrupts are NOT
397 : * masked.
398 : *
399 : * *c is set to the NEXT character
400 : */
401 : u_char *
402 0 : firstc(struct clist *clp, int *c)
403 : {
404 : u_char *cp;
405 :
406 0 : cc = clp->c_cc;
407 0 : if (cc == 0)
408 0 : return NULL;
409 0 : cp = clp->c_cf;
410 0 : *c = *cp & 0xff;
411 0 : if (clp->c_cq) {
412 0 : if (isset(clp->c_cq, cp - clp->c_cs))
413 0 : *c |= TTY_QUOTE;
414 : }
415 0 : return clp->c_cf;
416 0 : }
417 :
418 : /*
419 : * Remove the last character in the clist and return it.
420 : */
421 : int
422 0 : unputc(struct clist *clp)
423 : {
424 : unsigned int c = -1;
425 : int s;
426 :
427 0 : s = spltty();
428 0 : if (clp->c_cc == 0)
429 : goto out;
430 :
431 0 : if (clp->c_cl == clp->c_cs)
432 0 : clp->c_cl = clp->c_ce - 1;
433 : else
434 0 : --clp->c_cl;
435 0 : clp->c_cc--;
436 :
437 0 : c = *clp->c_cl & 0xff;
438 0 : *clp->c_cl = 0;
439 0 : if (clp->c_cq) {
440 0 : if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
441 0 : c |= TTY_QUOTE;
442 0 : clrbit(clp->c_cq, clp->c_cl - clp->c_cs);
443 0 : }
444 0 : if (clp->c_cc == 0)
445 0 : clp->c_cf = clp->c_cl = NULL;
446 : out:
447 0 : splx(s);
448 0 : return c;
449 : }
450 :
451 : /*
452 : * Put the chars in the from queue on the end of the to queue.
453 : */
454 : void
455 0 : catq(struct clist *from, struct clist *to)
456 : {
457 : int c;
458 : int s;
459 :
460 0 : s = spltty();
461 0 : if (from->c_cc == 0) { /* nothing to move */
462 0 : splx(s);
463 0 : return;
464 : }
465 :
466 : /*
467 : * if `to' queue is empty and the queues are the same max size,
468 : * it is more efficient to just swap the clist structures.
469 : */
470 0 : if (to->c_cc == 0 && from->c_cn == to->c_cn) {
471 0 : struct clist tmp;
472 :
473 0 : tmp = *from;
474 0 : *from = *to;
475 0 : *to = tmp;
476 0 : splx(s);
477 : return;
478 0 : }
479 0 : splx(s);
480 :
481 0 : while ((c = getc(from)) != -1)
482 0 : putc(c, to);
483 0 : }
|