tty_subr.c revision 1.1 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 1993/07/12 11:35:18 mycroft 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 || flag == 0)
192 goto out;
193
194 i = clp->c_cf - clp->c_cs;
195 while (cc-- > 0 && (clp->c_cs[i++] & flag) == 0) {
196 count++;
197 if (i == clp->c_cn)
198 break;
199 }
200 out:
201 splx(s);
202 return count;
203 }
204
205 /*
206 * Flush count bytes from clist.
207 */
208 void
209 ndflush(clp, count)
210 struct clist *clp;
211 int count;
212 {
213 register int cc;
214 int s;
215
216 s = spltty();
217 if (count == clp->c_cc) {
218 clp->c_cc = 0;
219 clp->c_cf = clp->c_cl = (u_char *)0;
220 goto out;
221 }
222 /* optimize this while loop */
223 while (count > 0 && clp->c_cc > 0) {
224 cc = clp->c_cl - clp->c_cf;
225 if (clp->c_cf >= clp->c_cl)
226 cc = clp->c_ce - clp->c_cf;
227 if (cc > count)
228 cc = count;
229 count -= cc;
230 clp->c_cc -= cc;
231 clp->c_cf += cc;
232 if (clp->c_cf == clp->c_ce)
233 clp->c_cf = clp->c_cs;
234 }
235 if (clp->c_cc == 0)
236 clp->c_cf = clp->c_cl = (u_char *)0;
237 out:
238 splx(s);
239 }
240
241 /*
242 * Put a character into the output queue.
243 */
244 int
245 putc(c, clp)
246 int c;
247 struct clist *clp;
248 {
249 register u_char *q;
250 register int i;
251 int r = -1;
252 int s;
253
254 s = spltty();
255 if (clp->c_cc == clp->c_cn)
256 goto out;
257
258 if (clp->c_cc == 0) {
259 if (!clp->c_cs) {
260 #if defined(DIAGNOSTIC) || 1
261 printf("b_to_q: required clalloc\n");
262 #endif
263 if(clalloc(clp, 1024, 1)) {
264 out:
265 splx(s);
266 return -1;
267 }
268 }
269 clp->c_cf = clp->c_cl = clp->c_cs;
270 }
271
272 *clp->c_cl = c & 0xff;
273 i = clp->c_cl - clp->c_cs;
274 if (clp->c_cq) {
275 #ifdef QBITS
276 if (c & TTY_QUOTE)
277 setbit(clp->c_cq, i);
278 else
279 clrbit(clp->c_cq, i);
280 #else
281 q = clp->c_cq + i;
282 *q = (c & TTY_QUOTE) ? 1 : 0;
283 #endif
284 }
285 clp->c_cc++;
286 clp->c_cl++;
287 if (clp->c_cl == clp->c_ce)
288 clp->c_cl = clp->c_cs;
289 splx(s);
290 return 0;
291 }
292
293 #ifdef QBITS
294 /*
295 * optimized version of
296 *
297 * for (i = 0; i < len; i++)
298 * clrbit(cp, off + len);
299 */
300 void
301 clrbits(cp, off, len)
302 u_char *cp;
303 int off;
304 int len;
305 {
306 int sby, sbi, eby, ebi;
307 register int i;
308 u_char mask;
309
310 if(len==1) {
311 clrbit(cp, off);
312 return;
313 }
314
315 sby = off / NBBY;
316 sbi = off % NBBY;
317 eby = (off+len) / NBBY;
318 ebi = (off+len) % NBBY;
319 if (sby == eby) {
320 mask = ((1 << (ebi - sbi)) - 1) << sbi;
321 cp[sby] &= ~mask;
322 } else {
323 mask = (1<<sbi) - 1;
324 cp[sby++] &= mask;
325
326 mask = (1<<ebi) - 1;
327 cp[eby] &= ~mask;
328
329 for (i = sby; i < eby; i++)
330 cp[i] = 0x00;
331 }
332 }
333 #endif
334
335 /*
336 * Copy buffer to clist.
337 * Return number of bytes not transfered.
338 */
339 int
340 b_to_q(cp, count, clp)
341 u_char *cp;
342 int count;
343 struct clist *clp;
344 {
345 register int i, cc;
346 register u_char *p = cp;
347 int off, s;
348
349 if (count <= 0)
350 return 0;
351
352 s = spltty();
353 if (clp->c_cc == clp->c_cn)
354 goto out;
355
356 if (clp->c_cc == 0) {
357 if (!clp->c_cs) {
358 #if defined(DIAGNOSTIC) || 1
359 printf("b_to_q: required clalloc\n");
360 #endif
361 if(clalloc(clp, 1024, 1))
362 goto out;
363 }
364 clp->c_cf = clp->c_cl = clp->c_cs;
365 }
366
367 /* optimize this while loop */
368 while (count > 0 && clp->c_cc < clp->c_cn) {
369 cc = clp->c_ce - clp->c_cl;
370 if (clp->c_cf > clp->c_cl)
371 cc = clp->c_cf - clp->c_cl;
372 if (cc > count)
373 cc = count;
374 bcopy(p, clp->c_cl, cc);
375 if (clp->c_cq) {
376 #ifdef QBITS
377 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
378 #else
379 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
380 #endif
381 }
382 p += cc;
383 count -= cc;
384 clp->c_cc += cc;
385 clp->c_cl += cc;
386 if (clp->c_cl == clp->c_ce)
387 clp->c_cl = clp->c_cs;
388 }
389 out:
390 splx(s);
391 return count;
392 }
393
394 static int cc;
395
396 /*
397 * Given a non-NULL pointer into the clist return the pointer
398 * to the next character in the list or return NULL if no more chars.
399 *
400 * Callers must not allow getc's to happen between firstc's and getc's
401 * so that the pointer becomes invalid. Note that interrupts are NOT
402 * masked.
403 */
404 u_char *
405 nextc(clp, cp, c)
406 struct clist *clp;
407 register u_char *cp;
408 int *c;
409 {
410
411 if (clp->c_cf == cp) {
412 /*
413 * First time initialization.
414 */
415 cc = clp->c_cc;
416 }
417 if (cc == 0 || cp == NULL)
418 return NULL;
419 if (--cc == 0)
420 return NULL;
421 if (++cp == clp->c_ce)
422 cp = clp->c_cs;
423 *c = *cp & 0xff;
424 if (clp->c_cq) {
425 #ifdef QBITS
426 if (isset(clp->c_cq, cp - clp->c_cs))
427 *c |= TTY_QUOTE;
428 #else
429 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
430 *c |= TTY_QUOTE;
431 #endif
432 }
433 return cp;
434 }
435
436 /*
437 * Given a non-NULL pointer into the clist return the pointer
438 * to the first character in the list or return NULL if no more chars.
439 *
440 * Callers must not allow getc's to happen between firstc's and getc's
441 * so that the pointer becomes invalid. Note that interrupts are NOT
442 * masked.
443 *
444 * *c is set to the NEXT character
445 */
446 u_char *
447 firstc(clp, c)
448 struct clist *clp;
449 int *c;
450 {
451 int empty = 0;
452 register u_char *cp;
453 register int i;
454
455 cc = clp->c_cc;
456 if (cc == 0)
457 return NULL;
458 cp = clp->c_cf;
459 *c = *cp & 0xff;
460 if(clp->c_cq) {
461 #ifdef QBITS
462 if (isset(clp->c_cq, cp - clp->c_cs))
463 *c |= TTY_QUOTE;
464 #else
465 if (*(cp - clp->c_cs + clp->c_cq))
466 *c |= TTY_QUOTE;
467 #endif
468 }
469 return clp->c_cf;
470 }
471
472 /*
473 * Remove the last character in the clist and return it.
474 */
475 int
476 unputc(clp)
477 struct clist *clp;
478 {
479 unsigned int c = -1;
480 int s;
481
482 s = spltty();
483 if (clp->c_cc == 0)
484 goto out;
485
486 if (clp->c_cl == clp->c_cs)
487 clp->c_cl = clp->c_ce - 1;
488 else
489 --clp->c_cl;
490 clp->c_cc--;
491
492 c = *clp->c_cl & 0xff;
493 if (clp->c_cq) {
494 #ifdef QBITS
495 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
496 c |= TTY_QUOTE;
497 #else
498 if (*(clp->c_cf - clp->c_cs + clp->c_cq))
499 c | TTY_QUOTE;
500 #endif
501 }
502 if (clp->c_cc == 0)
503 clp->c_cf = clp->c_cl = (u_char *)0;
504 out:
505 splx(s);
506 return c;
507 }
508
509 /*
510 * Put the chars in the from queue on the end of the to queue.
511 */
512 void
513 catq(from, to)
514 struct clist *from, *to;
515 {
516 int c;
517
518 while ((c = getc(from)) != -1)
519 putc(c, to);
520 }
521