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