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