tty_subr.c revision 1.17 1 /* $NetBSD: tty_subr.c,v 1.17 1998/08/04 04:03:17 perry 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/param.h>
37 #include <sys/systm.h>
38 #include <sys/buf.h>
39 #include <sys/ioctl.h>
40 #include <sys/tty.h>
41 #ifdef REAL_CLISTS
42 #include <sys/clist.h>
43 #endif
44 #include <sys/malloc.h>
45
46 /*
47 * At compile time, choose:
48 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
49 * defined we allocate an array of bits -- 1/8th as much memory but
50 * setbit(), clrbit(), and isset() take more cpu. If QBITS is
51 * undefined, we just use an array of bytes.
52 *
53 * If TTY_QUOTE functionality isn't required by a line discipline,
54 * it can free c_cq and set it to NULL. This speeds things up,
55 * and also does not use any extra memory. This is useful for (say)
56 * a SLIP line discipline that wants a 32K ring buffer for data
57 * but doesn't need quoting.
58 */
59 #define QBITS
60
61 #ifdef QBITS
62 #define QMEM(n) ((((n)-1)/NBBY)+1)
63 #else
64 #define QMEM(n) (n)
65 #endif
66
67 void cinit __P((void));
68 #ifdef QBITS
69 void clrbits __P((u_char *, int, int));
70 #endif
71
72 /*
73 * Initialize clists.
74 */
75 void
76 cinit()
77 {
78 }
79
80 /*
81 * Initialize a particular clist. Ok, they are really ring buffers,
82 * of the specified length, with/without quoting support.
83 */
84 int
85 clalloc(clp, size, quot)
86 struct clist *clp;
87 int size;
88 int quot;
89 {
90
91 MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
92 if (!clp->c_cs)
93 return (-1);
94 memset(clp->c_cs, 0, size);
95
96 if(quot) {
97 MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
98 if (!clp->c_cq) {
99 FREE(clp->c_cs, M_TTYS);
100 return (-1);
101 }
102 memset(clp->c_cs, 0, QMEM(size));
103 } else
104 clp->c_cq = (u_char *)0;
105
106 clp->c_cf = clp->c_cl = (u_char *)0;
107 clp->c_ce = clp->c_cs + size;
108 clp->c_cn = size;
109 clp->c_cc = 0;
110 return (0);
111 }
112
113 void
114 clfree(clp)
115 struct clist *clp;
116 {
117 if(clp->c_cs)
118 FREE(clp->c_cs, M_TTYS);
119 if(clp->c_cq)
120 FREE(clp->c_cq, M_TTYS);
121 clp->c_cs = clp->c_cq = (u_char *)0;
122 }
123
124
125 /*
126 * Get a character from a clist.
127 */
128 int
129 getc(clp)
130 struct clist *clp;
131 {
132 register int c = -1;
133 int s;
134
135 s = spltty();
136 if (clp->c_cc == 0)
137 goto out;
138
139 c = *clp->c_cf & 0xff;
140 if (clp->c_cq) {
141 #ifdef QBITS
142 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
143 c |= TTY_QUOTE;
144 #else
145 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
146 c |= TTY_QUOTE;
147 #endif
148 }
149 if (++clp->c_cf == clp->c_ce)
150 clp->c_cf = clp->c_cs;
151 if (--clp->c_cc == 0)
152 clp->c_cf = clp->c_cl = (u_char *)0;
153 out:
154 splx(s);
155 return c;
156 }
157
158 /*
159 * Copy clist to buffer.
160 * Return number of bytes moved.
161 */
162 int
163 q_to_b(clp, cp, count)
164 struct clist *clp;
165 u_char *cp;
166 int count;
167 {
168 register int cc;
169 u_char *p = cp;
170 int s;
171
172 s = spltty();
173 /* optimize this while loop */
174 while (count > 0 && clp->c_cc > 0) {
175 cc = clp->c_cl - clp->c_cf;
176 if (clp->c_cf >= clp->c_cl)
177 cc = clp->c_ce - clp->c_cf;
178 if (cc > count)
179 cc = count;
180 memcpy(p, clp->c_cf, cc);
181 count -= cc;
182 p += cc;
183 clp->c_cc -= cc;
184 clp->c_cf += cc;
185 if (clp->c_cf == clp->c_ce)
186 clp->c_cf = clp->c_cs;
187 }
188 if (clp->c_cc == 0)
189 clp->c_cf = clp->c_cl = (u_char *)0;
190 splx(s);
191 return p - cp;
192 }
193
194 /*
195 * Return count of contiguous characters in clist.
196 * Stop counting if flag&character is non-null.
197 */
198 int
199 ndqb(clp, flag)
200 struct clist *clp;
201 int flag;
202 {
203 int count = 0;
204 register int i;
205 register int cc;
206 int s;
207
208 s = spltty();
209 if ((cc = clp->c_cc) == 0)
210 goto out;
211
212 if (flag == 0) {
213 count = clp->c_cl - clp->c_cf;
214 if (count <= 0)
215 count = clp->c_ce - clp->c_cf;
216 goto out;
217 }
218
219 i = clp->c_cf - clp->c_cs;
220 if (flag & TTY_QUOTE) {
221 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
222 isset(clp->c_cq, i))) {
223 count++;
224 if (i == clp->c_cn)
225 break;
226 }
227 } else {
228 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
229 count++;
230 if (i == clp->c_cn)
231 break;
232 }
233 }
234 out:
235 splx(s);
236 return count;
237 }
238
239 /*
240 * Flush count bytes from clist.
241 */
242 void
243 ndflush(clp, count)
244 struct clist *clp;
245 int count;
246 {
247 register int cc;
248 int s;
249
250 s = spltty();
251 if (count == clp->c_cc) {
252 clp->c_cc = 0;
253 clp->c_cf = clp->c_cl = (u_char *)0;
254 goto out;
255 }
256 /* optimize this while loop */
257 while (count > 0 && clp->c_cc > 0) {
258 cc = clp->c_cl - clp->c_cf;
259 if (clp->c_cf >= clp->c_cl)
260 cc = clp->c_ce - clp->c_cf;
261 if (cc > count)
262 cc = count;
263 count -= cc;
264 clp->c_cc -= cc;
265 clp->c_cf += cc;
266 if (clp->c_cf == clp->c_ce)
267 clp->c_cf = clp->c_cs;
268 }
269 if (clp->c_cc == 0)
270 clp->c_cf = clp->c_cl = (u_char *)0;
271 out:
272 splx(s);
273 }
274
275 /*
276 * Put a character into the output queue.
277 */
278 int
279 putc(c, clp)
280 int c;
281 struct clist *clp;
282 {
283 register int i;
284 int s;
285
286 s = spltty();
287 if (clp->c_cc == clp->c_cn)
288 goto out;
289
290 if (clp->c_cc == 0) {
291 if (!clp->c_cs) {
292 #if defined(DIAGNOSTIC) || 1
293 printf("putc: required clalloc\n");
294 #endif
295 if(clalloc(clp, 1024, 1)) {
296 out:
297 splx(s);
298 return -1;
299 }
300 }
301 clp->c_cf = clp->c_cl = clp->c_cs;
302 }
303
304 *clp->c_cl = c & 0xff;
305 i = clp->c_cl - clp->c_cs;
306 if (clp->c_cq) {
307 #ifdef QBITS
308 if (c & TTY_QUOTE)
309 setbit(clp->c_cq, i);
310 else
311 clrbit(clp->c_cq, i);
312 #else
313 q = clp->c_cq + i;
314 *q = (c & TTY_QUOTE) ? 1 : 0;
315 #endif
316 }
317 clp->c_cc++;
318 clp->c_cl++;
319 if (clp->c_cl == clp->c_ce)
320 clp->c_cl = clp->c_cs;
321 splx(s);
322 return 0;
323 }
324
325 #ifdef QBITS
326 /*
327 * optimized version of
328 *
329 * for (i = 0; i < len; i++)
330 * clrbit(cp, off + len);
331 */
332 void
333 clrbits(cp, off, len)
334 u_char *cp;
335 int off;
336 int len;
337 {
338 int sby, sbi, eby, ebi;
339 register int i;
340 u_char mask;
341
342 if(len==1) {
343 clrbit(cp, off);
344 return;
345 }
346
347 sby = off / NBBY;
348 sbi = off % NBBY;
349 eby = (off+len) / NBBY;
350 ebi = (off+len) % NBBY;
351 if (sby == eby) {
352 mask = ((1 << (ebi - sbi)) - 1) << sbi;
353 cp[sby] &= ~mask;
354 } else {
355 mask = (1<<sbi) - 1;
356 cp[sby++] &= mask;
357
358 mask = (1<<ebi) - 1;
359 cp[eby] &= ~mask;
360
361 for (i = sby; i < eby; i++)
362 cp[i] = 0x00;
363 }
364 }
365 #endif
366
367 /*
368 * Copy buffer to clist.
369 * Return number of bytes not transfered.
370 */
371 int
372 b_to_q(cp, count, clp)
373 const u_char *cp;
374 int count;
375 struct clist *clp;
376 {
377 register int cc;
378 register const u_char *p = cp;
379 int s;
380
381 if (count <= 0)
382 return 0;
383
384 s = spltty();
385 if (clp->c_cc == clp->c_cn)
386 goto out;
387
388 if (clp->c_cc == 0) {
389 if (!clp->c_cs) {
390 #if defined(DIAGNOSTIC) || 1
391 printf("b_to_q: required clalloc\n");
392 #endif
393 if(clalloc(clp, 1024, 1))
394 goto out;
395 }
396 clp->c_cf = clp->c_cl = clp->c_cs;
397 }
398
399 /* optimize this while loop */
400 while (count > 0 && clp->c_cc < clp->c_cn) {
401 cc = clp->c_ce - clp->c_cl;
402 if (clp->c_cf > clp->c_cl)
403 cc = clp->c_cf - clp->c_cl;
404 if (cc > count)
405 cc = count;
406 memcpy(clp->c_cl, p, cc);
407 if (clp->c_cq) {
408 #ifdef QBITS
409 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
410 #else
411 memset(clp->c_cl - clp->c_cs + clp->c_cq, 0, cc);
412 #endif
413 }
414 p += cc;
415 count -= cc;
416 clp->c_cc += cc;
417 clp->c_cl += cc;
418 if (clp->c_cl == clp->c_ce)
419 clp->c_cl = clp->c_cs;
420 }
421 out:
422 splx(s);
423 return count;
424 }
425
426 static int cc;
427
428 /*
429 * Given a non-NULL pointer into the clist return the pointer
430 * to the next character in the list or return NULL if no more chars.
431 *
432 * Callers must not allow getc's to happen between firstc's and getc's
433 * so that the pointer becomes invalid. Note that interrupts are NOT
434 * masked.
435 */
436 u_char *
437 nextc(clp, cp, c)
438 struct clist *clp;
439 register u_char *cp;
440 int *c;
441 {
442
443 if (clp->c_cf == cp) {
444 /*
445 * First time initialization.
446 */
447 cc = clp->c_cc;
448 }
449 if (cc == 0 || cp == NULL)
450 return NULL;
451 if (--cc == 0)
452 return NULL;
453 if (++cp == clp->c_ce)
454 cp = clp->c_cs;
455 *c = *cp & 0xff;
456 if (clp->c_cq) {
457 #ifdef QBITS
458 if (isset(clp->c_cq, cp - clp->c_cs))
459 *c |= TTY_QUOTE;
460 #else
461 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
462 *c |= TTY_QUOTE;
463 #endif
464 }
465 return cp;
466 }
467
468 /*
469 * Given a non-NULL pointer into the clist return the pointer
470 * to the first character in the list or return NULL if no more chars.
471 *
472 * Callers must not allow getc's to happen between firstc's and getc's
473 * so that the pointer becomes invalid. Note that interrupts are NOT
474 * masked.
475 *
476 * *c is set to the NEXT character
477 */
478 u_char *
479 firstc(clp, c)
480 struct clist *clp;
481 int *c;
482 {
483 register u_char *cp;
484
485 cc = clp->c_cc;
486 if (cc == 0)
487 return NULL;
488 cp = clp->c_cf;
489 *c = *cp & 0xff;
490 if(clp->c_cq) {
491 #ifdef QBITS
492 if (isset(clp->c_cq, cp - clp->c_cs))
493 *c |= TTY_QUOTE;
494 #else
495 if (*(cp - clp->c_cs + clp->c_cq))
496 *c |= TTY_QUOTE;
497 #endif
498 }
499 return clp->c_cf;
500 }
501
502 /*
503 * Remove the last character in the clist and return it.
504 */
505 int
506 unputc(clp)
507 struct clist *clp;
508 {
509 unsigned int c = -1;
510 int s;
511
512 s = spltty();
513 if (clp->c_cc == 0)
514 goto out;
515
516 if (clp->c_cl == clp->c_cs)
517 clp->c_cl = clp->c_ce - 1;
518 else
519 --clp->c_cl;
520 clp->c_cc--;
521
522 c = *clp->c_cl & 0xff;
523 if (clp->c_cq) {
524 #ifdef QBITS
525 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
526 c |= TTY_QUOTE;
527 #else
528 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
529 c |= TTY_QUOTE;
530 #endif
531 }
532 if (clp->c_cc == 0)
533 clp->c_cf = clp->c_cl = (u_char *)0;
534 out:
535 splx(s);
536 return c;
537 }
538
539 /*
540 * Put the chars in the from queue on the end of the to queue.
541 */
542 void
543 catq(from, to)
544 struct clist *from, *to;
545 {
546 int c;
547
548 while ((c = getc(from)) != -1)
549 putc(c, to);
550 }
551