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