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