1 /* $OpenBSD: tty_subr.c,v 1.18 2005/12/21 12:43:49 jsg Exp $ */
2 /* $NetBSD: tty_subr.c,v 1.13 1996/02/09 19:00:43 christos Exp $ */
3
4 /*
5 * Copyright (c) 1993, 1994 Theo de Raadt
6 * All rights reserved.
7 *
8 * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
9 * set of true clist functions that this is very loosely based on.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/buf.h>
35 #include <sys/ioctl.h>
36 #include <sys/tty.h>
37 #include <sys/malloc.h>
38
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 QMEM(n) ((((n)-1)/NBBY)+1)
47
48 void cinit(void);
49 void clrbits(u_char *, int, int);
50
51 /*
52 * Initialize clists.
53 */
54 void
55 cinit(void)
56 {
57 }
58
59 /*
60 * Initialize a particular clist. Ok, they are really ring buffers,
61 * of the specified length, with/without quoting support.
62 */
63 int
64 clalloc(struct clist *clp, int size, int quot)
65 {
66
67 clp->c_cs = malloc(size, M_TTYS, M_WAITOK);
68 bzero(clp->c_cs, size);
69
70 if (quot) {
71 clp->c_cq = malloc(QMEM(size), M_TTYS, M_WAITOK);
72 bzero(clp->c_cq, QMEM(size));
73 } else
74 clp->c_cq = (u_char *)0;
75
76 clp->c_cf = clp->c_cl = (u_char *)0;
77 clp->c_ce = clp->c_cs + size;
78 clp->c_cn = size;
79 clp->c_cc = 0;
80 return (0);
81 }
82
83 void
84 clfree(struct clist *clp)
85 {
86 if (clp->c_cs) {
87 bzero(clp->c_cs, clp->c_cn);
88 free(clp->c_cs, M_TTYS);
89 }
90 if (clp->c_cq) {
91 bzero(clp->c_cq, QMEM(clp->c_cn));
92 free(clp->c_cq, M_TTYS);
93 }
94 clp->c_cs = clp->c_cq = (u_char *)0;
95 }
96
97
98 /*
99 * Get a character from a clist.
100 */
101 int
102 getc(struct clist *clp)
103 {
104 int c = -1;
105 int s;
106
107 s = spltty();
108 if (clp->c_cc == 0)
109 goto out;
110
111 c = *clp->c_cf & 0xff;
112 if (clp->c_cq) {
113 if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
114 c |= TTY_QUOTE;
115 }
116 if (++clp->c_cf == clp->c_ce)
117 clp->c_cf = clp->c_cs;
118 if (--clp->c_cc == 0)
119 clp->c_cf = clp->c_cl = (u_char *)0;
120 out:
121 splx(s);
122 return c;
123 }
124
125 /*
126 * Copy clist to buffer.
127 * Return number of bytes moved.
128 */
129 int
130 q_to_b(struct clist *clp, u_char *cp, int count)
131 {
132 int cc;
133 u_char *p = cp;
134 int s;
135
136 s = spltty();
137 /* optimize this while loop */
138 while (count > 0 && clp->c_cc > 0) {
139 cc = clp->c_cl - clp->c_cf;
140 if (clp->c_cf >= clp->c_cl)
141 cc = clp->c_ce - clp->c_cf;
142 if (cc > count)
143 cc = count;
144 bcopy(clp->c_cf, p, cc);
145 count -= cc;
146 p += cc;
147 clp->c_cc -= cc;
148 clp->c_cf += cc;
149 if (clp->c_cf == clp->c_ce)
150 clp->c_cf = clp->c_cs;
151 }
152 if (clp->c_cc == 0)
153 clp->c_cf = clp->c_cl = (u_char *)0;
154 splx(s);
155 return p - cp;
156 }
157
158 /*
159 * Return count of contiguous characters in clist.
160 * Stop counting if flag&character is non-null.
161 */
162 int
163 ndqb(struct clist *clp, int flag)
164 {
165 int count = 0;
166 int i;
167 int cc;
168 int s;
169
170 s = spltty();
171 if ((cc = clp->c_cc) == 0)
172 goto out;
173
174 if (flag == 0) {
175 count = clp->c_cl - clp->c_cf;
176 if (count <= 0)
177 count = clp->c_ce - clp->c_cf;
178 goto out;
179 }
180
181 i = clp->c_cf - clp->c_cs;
182 if (flag & TTY_QUOTE) {
183 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
184 isset(clp->c_cq, i))) {
185 count++;
186 if (i == clp->c_cn)
187 break;
188 }
189 } else {
190 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
191 count++;
192 if (i == clp->c_cn)
193 break;
194 }
195 }
196 out:
197 splx(s);
198 return count;
199 }
200
201 /*
202 * Flush count bytes from clist.
203 */
204 void
205 ndflush(struct clist *clp, int count)
206 {
207 int cc;
208 int s;
209
210 s = spltty();
211 if (count == clp->c_cc) {
212 clp->c_cc = 0;
213 clp->c_cf = clp->c_cl = (u_char *)0;
214 goto out;
215 }
216 /* optimize this while loop */
217 while (count > 0 && clp->c_cc > 0) {
218 cc = clp->c_cl - clp->c_cf;
219 if (clp->c_cf >= clp->c_cl)
220 cc = clp->c_ce - clp->c_cf;
221 if (cc > count)
222 cc = count;
223 count -= cc;
224 clp->c_cc -= cc;
225 clp->c_cf += cc;
226 if (clp->c_cf == clp->c_ce)
227 clp->c_cf = clp->c_cs;
228 }
229 if (clp->c_cc == 0)
230 clp->c_cf = clp->c_cl = (u_char *)0;
231 out:
232 splx(s);
233 }
234
235 /*
236 * Put a character into the output queue.
237 */
238 int
239 putc(int c, struct clist *clp)
240 {
241 int i;
242 int s;
243
244 s = spltty();
245 if (clp->c_cc == clp->c_cn)
246 goto out;
247
248 if (clp->c_cc == 0) {
249 if (!clp->c_cs) {
250 #if defined(DIAGNOSTIC) || 1
251 printf("putc: required clalloc\n");
252 #endif
253 if (clalloc(clp, 1024, 1)) {
254 out:
255 splx(s);
256 return -1;
257 }
258 }
259 clp->c_cf = clp->c_cl = clp->c_cs;
260 }
261
262 *clp->c_cl = c & 0xff;
263 i = clp->c_cl - clp->c_cs;
264 if (clp->c_cq) {
265 if (c & TTY_QUOTE)
266 setbit(clp->c_cq, i);
267 else
268 clrbit(clp->c_cq, i);
269 }
270 clp->c_cc++;
271 clp->c_cl++;
272 if (clp->c_cl == clp->c_ce)
273 clp->c_cl = clp->c_cs;
274 splx(s);
275 return 0;
276 }
277
278 /*
279 * optimized version of
280 *
281 * for (i = 0; i < len; i++)
282 * clrbit(cp, off + len);
283 */
284 void
285 clrbits(u_char *cp, int off, int len)
286 {
287 int sby, sbi, eby, ebi;
288 int i;
289 u_char mask;
290
291 if (len==1) {
292 clrbit(cp, off);
293 return;
294 }
295
296 sby = off / NBBY;
297 sbi = off % NBBY;
298 eby = (off+len) / NBBY;
299 ebi = (off+len) % NBBY;
300 if (sby == eby) {
301 mask = ((1 << (ebi - sbi)) - 1) << sbi;
302 cp[sby] &= ~mask;
303 } else {
304 mask = (1<<sbi) - 1;
305 cp[sby++] &= mask;
306
307 mask = (1<<ebi) - 1;
308 cp[eby] &= ~mask;
309
310 for (i = sby; i < eby; i++)
311 cp[i] = 0x00;
312 }
313 }
314
315 /*
316 * Copy buffer to clist.
317 * Return number of bytes not transferred.
318 */
319 int
320 b_to_q(u_char *cp, int count, struct clist *clp)
321 {
322 int cc;
323 u_char *p = cp;
324 int s;
325
326 if (count <= 0)
327 return 0;
328
329 s = spltty();
330 if (clp->c_cc == clp->c_cn)
331 goto out;
332
333 if (clp->c_cc == 0) {
334 if (!clp->c_cs) {
335 #if defined(DIAGNOSTIC) || 1
336 printf("b_to_q: required clalloc\n");
337 #endif
338 if (clalloc(clp, 1024, 1))
339 goto out;
340 }
341 clp->c_cf = clp->c_cl = clp->c_cs;
342 }
343
344 /* optimize this while loop */
345 while (count > 0 && clp->c_cc < clp->c_cn) {
346 cc = clp->c_ce - clp->c_cl;
347 if (clp->c_cf > clp->c_cl)
348 cc = clp->c_cf - clp->c_cl;
349 if (cc > count)
350 cc = count;
351 bcopy(p, clp->c_cl, cc);
352 if (clp->c_cq) {
353 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
354 }
355 p += cc;
356 count -= cc;
357 clp->c_cc += cc;
358 clp->c_cl += cc;
359 if (clp->c_cl == clp->c_ce)
360 clp->c_cl = clp->c_cs;
361 }
362 out:
363 splx(s);
364 return count;
365 }
366
367 static int cc;
368
369 /*
370 * Given a non-NULL pointer into the clist return the pointer
371 * to the next character in the list or return NULL if no more chars.
372 *
373 * Callers must not allow getc's to happen between firstc's and getc's
374 * so that the pointer becomes invalid. Note that interrupts are NOT
375 * masked.
376 */
377 u_char *
378 nextc(struct clist *clp, u_char *cp, int *c)
379 {
380
381 if (clp->c_cf == cp) {
382 /*
383 * First time initialization.
384 */
385 cc = clp->c_cc;
386 }
387 if (cc == 0 || cp == NULL)
388 return NULL;
389 if (--cc == 0)
390 return NULL;
391 if (++cp == clp->c_ce)
392 cp = clp->c_cs;
393 *c = *cp & 0xff;
394 if (clp->c_cq) {
395 if (isset(clp->c_cq, cp - clp->c_cs))
396 *c |= TTY_QUOTE;
397 }
398 return cp;
399 }
400
401 /*
402 * Given a non-NULL pointer into the clist return the pointer
403 * to the first character in the list or return NULL if no more chars.
404 *
405 * Callers must not allow getc's to happen between firstc's and getc's
406 * so that the pointer becomes invalid. Note that interrupts are NOT
407 * masked.
408 *
409 * *c is set to the NEXT character
410 */
411 u_char *
412 firstc(struct clist *clp, int *c)
413 {
414 u_char *cp;
415
416 cc = clp->c_cc;
417 if (cc == 0)
418 return NULL;
419 cp = clp->c_cf;
420 *c = *cp & 0xff;
421 if (clp->c_cq) {
422 if (isset(clp->c_cq, cp - clp->c_cs))
423 *c |= TTY_QUOTE;
424 }
425 return clp->c_cf;
426 }
427
428 /*
429 * Remove the last character in the clist and return it.
430 */
431 int
432 unputc(struct clist *clp)
433 {
434 unsigned int c = -1;
435 int s;
436
437 s = spltty();
438 if (clp->c_cc == 0)
439 goto out;
440
441 if (clp->c_cl == clp->c_cs)
442 clp->c_cl = clp->c_ce - 1;
443 else
444 --clp->c_cl;
445 clp->c_cc--;
446
447 c = *clp->c_cl & 0xff;
448 if (clp->c_cq) {
449 if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
450 c |= TTY_QUOTE;
451 }
452 if (clp->c_cc == 0)
453 clp->c_cf = clp->c_cl = (u_char *)0;
454 out:
455 splx(s);
456 return c;
457 }
458
459 /*
460 * Put the chars in the from queue on the end of the to queue.
461 */
462 void
463 catq(struct clist *from, struct clist *to)
464 {
465 int c;
466 int s;
467
468 s = spltty();
469 if (from->c_cc == 0) { /* nothing to move */
470 splx(s);
471 return;
472 }
473
474 /*
475 * if `to' queue is empty and the queues are the same max size,
476 * it is more efficient to just swap the clist structures.
477 */
478 if (to->c_cc == 0 && from->c_cn == to->c_cn) {
479 struct clist tmp;
480
481 tmp = *from;
482 *from = *to;
483 *to = tmp;
484 splx(s);
485 return;
486 }
487 splx(s);
488
489 while ((c = getc(from)) != -1)
490 putc(c, to);
491 }