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