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