]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/tty_subr.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / tty_subr.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1993, 1994 Theo de Raadt
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice unmodified, this list of conditions, and the following
38 * disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 */
56
57 /*
58 * We use the NetBSD based clist system, it is much more efficient than the
59 * old style clist stuff used by free bsd.
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/ioctl.h>
65 #include <sys/tty.h>
66 #include <sys/malloc.h>
67
68
69 /*
70 * At compile time, choose:
71 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
72 * defined we allocate an array of bits -- 1/8th as much memory but
73 * setbit(), clrbit(), and isset() take more cpu. If QBITS is
74 * undefined, we just use an array of bytes.
75 *
76 * If TTY_QUOTE functionality isn't required by a line discipline,
77 * it can free c_cq and set it to NULL. This speeds things up,
78 * and also does not use any extra memory. This is useful for (say)
79 * a SLIP line discipline that wants a 32K ring buffer for data
80 * but doesn't need quoting.
81 */
82 #define QBITS
83
84 #ifdef QBITS
85 #define QMEM(n) ((((n)-1)/NBBY)+1)
86 #else
87 #define QMEM(n) (n)
88 #endif
89
90
91 /*
92 * Initialize clists.
93 */
94 void
95 cinit(void)
96 {
97 }
98
99 /*
100 * Initialize a particular clist. Ok, they are really ring buffers,
101 * of the specified length, with/without quoting support.
102 */
103 int
104 clalloc(struct clist *clp, int size, int quot)
105 {
106 clp->c_cs = kheap_alloc(KHEAP_DATA_BUFFERS, size, Z_WAITOK | Z_ZERO);
107 if (!clp->c_cs) {
108 return -1;
109 }
110
111 if (quot) {
112 clp->c_cq = kheap_alloc(KHEAP_DATA_BUFFERS,
113 QMEM(size), Z_WAITOK | Z_ZERO);
114 if (!clp->c_cq) {
115 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cs, size);
116 return -1;
117 }
118 } else {
119 clp->c_cq = (u_char *)0;
120 }
121
122 clp->c_cf = clp->c_cl = (u_char *)0;
123 clp->c_ce = clp->c_cs + size;
124 clp->c_cn = size;
125 clp->c_cc = 0;
126 return 0;
127 }
128
129 void
130 clfree(struct clist *clp)
131 {
132 if (clp->c_cs) {
133 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cs, clp->c_cn);
134 }
135 if (clp->c_cq) {
136 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cq, QMEM(clp->c_cn));
137 }
138 clp->c_cs = clp->c_cq = (u_char *)0;
139 }
140
141
142 /*
143 * Get a character from a clist.
144 */
145 int
146 getc(struct clist *clp)
147 {
148 int c = -1;
149
150 if (clp->c_cc == 0) {
151 goto out;
152 }
153
154 c = *clp->c_cf & 0xff;
155 if (clp->c_cq) {
156 #ifdef QBITS
157 if (isset(clp->c_cq, clp->c_cf - clp->c_cs)) {
158 c |= TTY_QUOTE;
159 }
160 #else
161 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
162 c |= TTY_QUOTE;
163 }
164 #endif
165 }
166 if (++clp->c_cf == clp->c_ce) {
167 clp->c_cf = clp->c_cs;
168 }
169 if (--clp->c_cc == 0) {
170 clp->c_cf = clp->c_cl = (u_char *)0;
171 }
172 out:
173 return c;
174 }
175
176 /*
177 * Copy clist to buffer.
178 * Return number of bytes moved.
179 */
180 int
181 q_to_b(struct clist *clp, u_char *cp, int count)
182 {
183 size_t cc;
184 u_char *p = cp;
185
186 /* optimize this while loop */
187 while (count > 0 && clp->c_cc > 0) {
188 cc = clp->c_cl - clp->c_cf;
189 if (clp->c_cf >= clp->c_cl) {
190 cc = clp->c_ce - clp->c_cf;
191 }
192 if (cc > INT_MAX || (int)cc > count) {
193 cc = count;
194 }
195 bcopy(clp->c_cf, p, cc);
196 count -= cc;
197 p += cc;
198 clp->c_cc -= cc;
199 clp->c_cf += cc;
200 if (clp->c_cf == clp->c_ce) {
201 clp->c_cf = clp->c_cs;
202 }
203 }
204 if (clp->c_cc == 0) {
205 clp->c_cf = clp->c_cl = (u_char *)0;
206 }
207 return (int)MIN(INT32_MAX, p - cp);
208 }
209
210 /*
211 * Return count of contiguous characters in clist.
212 * Stop counting if flag&character is non-null.
213 */
214 int
215 ndqb(struct clist *clp, int flag)
216 {
217 size_t count = 0;
218 size_t i;
219 int cc;
220
221 if ((cc = clp->c_cc) == 0) {
222 goto out;
223 }
224
225 if (flag == 0) {
226 count = clp->c_cl - clp->c_cf;
227 if (count <= 0) {
228 count = clp->c_ce - clp->c_cf;
229 }
230 goto out;
231 }
232
233 i = clp->c_cf - clp->c_cs;
234 if (i > INT_MAX) {
235 return 0;
236 }
237 if (flag & TTY_QUOTE) {
238 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
239 isset(clp->c_cq, i))) {
240 count++;
241 if ((int)i == clp->c_cn) {
242 break;
243 }
244 }
245 } else {
246 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
247 count++;
248 if ((int)i == clp->c_cn) {
249 break;
250 }
251 }
252 }
253 out:
254 if (count > INT_MAX) {
255 return 0;
256 }
257 return (int)count;
258 }
259
260 /*
261 * Flush count bytes from clist.
262 */
263 void
264 ndflush(struct clist *clp, int count)
265 {
266 size_t cc;
267
268 if (count == clp->c_cc) {
269 clp->c_cc = 0;
270 clp->c_cf = clp->c_cl = (u_char *)0;
271 return;
272 }
273 /* optimize this while loop */
274 while (count > 0 && clp->c_cc > 0) {
275 cc = clp->c_cl - clp->c_cf;
276 if (clp->c_cf >= clp->c_cl) {
277 cc = clp->c_ce - clp->c_cf;
278 }
279 if (cc > INT_MAX || (int)cc > count) {
280 cc = count;
281 }
282 count -= cc;
283 clp->c_cc -= cc;
284 clp->c_cf += cc;
285 if (clp->c_cf == clp->c_ce) {
286 clp->c_cf = clp->c_cs;
287 }
288 }
289 if (clp->c_cc == 0) {
290 clp->c_cf = clp->c_cl = (u_char *)0;
291 }
292 }
293
294 /*
295 * Put a character into the output queue.
296 */
297 int
298 putc(int c, struct clist *clp)
299 {
300 size_t i;
301
302 if (clp->c_cc == 0) {
303 if (!clp->c_cs) {
304 #if DIAGNOSTIC
305 //printf("putc: required clalloc\n");
306 #endif
307 if (clalloc(clp, 1024, 1)) {
308 return -1;
309 }
310 }
311 clp->c_cf = clp->c_cl = clp->c_cs;
312 }
313
314 if (clp->c_cc == clp->c_cn) {
315 return -1;
316 }
317
318 *clp->c_cl = c & 0xff;
319 i = clp->c_cl - clp->c_cs;
320 if (i > INT_MAX) {
321 return -1;
322 }
323 if (clp->c_cq) {
324 #ifdef QBITS
325 if (c & TTY_QUOTE) {
326 setbit(clp->c_cq, i);
327 } else {
328 clrbit(clp->c_cq, i);
329 }
330 #else
331 q = clp->c_cq + i;
332 *q = (c & TTY_QUOTE) ? 1 : 0;
333 #endif
334 }
335 clp->c_cc++;
336 clp->c_cl++;
337 if (clp->c_cl == clp->c_ce) {
338 clp->c_cl = clp->c_cs;
339 }
340 return 0;
341 }
342
343 #ifdef QBITS
344 /*
345 * optimized version of
346 *
347 * for (i = 0; i < len; i++)
348 * clrbit(cp, off + len);
349 */
350 void
351 clrbits(u_char *cp, int off, int len)
352 {
353 int sby, sbi, eby, ebi;
354 int i;
355 u_char mask;
356
357 if (len == 1) {
358 clrbit(cp, off);
359 return;
360 }
361
362 sby = off / NBBY;
363 sbi = off % NBBY;
364 eby = (off + len) / NBBY;
365 ebi = (off + len) % NBBY;
366 if (sby == eby) {
367 mask = (u_char)(((1 << (ebi - sbi)) - 1) << sbi);
368 cp[sby] &= ~mask;
369 } else {
370 mask = (u_char)((1 << sbi) - 1);
371 cp[sby++] &= mask;
372
373 mask = (u_char)((1 << ebi) - 1);
374 /* handle remainder bits, if any, for a non-0 ebi value */
375 if (mask) {
376 cp[eby] &= ~mask;
377 }
378
379 for (i = sby; i < eby; i++) {
380 cp[i] = 0x00;
381 }
382 }
383 }
384 #endif
385
386 /*
387 * Copy buffer to clist.
388 * Return number of bytes not transfered.
389 */
390 int
391 b_to_q(const u_char *cp, int count, struct clist *clp)
392 {
393 size_t cc;
394 const u_char *p = cp;
395
396 if (count <= 0) {
397 return 0;
398 }
399
400
401 if (clp->c_cc == 0) {
402 if (!clp->c_cs) {
403 #if DIAGNOSTIC
404 printf("b_to_q: required clalloc\n");
405 #endif
406 if (clalloc(clp, 1024, 1)) {
407 goto out;
408 }
409 }
410 clp->c_cf = clp->c_cl = clp->c_cs;
411 }
412
413 if (clp->c_cc == clp->c_cn) {
414 goto out;
415 }
416
417 /* optimize this while loop */
418 while (count > 0 && clp->c_cc < clp->c_cn) {
419 cc = clp->c_ce - clp->c_cl;
420 if (clp->c_cf > clp->c_cl) {
421 cc = clp->c_cf - clp->c_cl;
422 }
423 if (cc > INT_MAX || (int)cc > count) {
424 cc = count;
425 }
426 bcopy(p, clp->c_cl, cc);
427 if (clp->c_cq) {
428 #ifdef QBITS
429 if (clp->c_cl - clp->c_cs > INT_MAX || cc > INT_MAX) {
430 count = 0;
431 goto out;
432 }
433 clrbits(clp->c_cq, (int)(clp->c_cl - clp->c_cs), (int)cc);
434 #else
435 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
436 #endif
437 }
438 p += cc;
439 count -= cc;
440 clp->c_cc += cc;
441 clp->c_cl += cc;
442 if (clp->c_cl == clp->c_ce) {
443 clp->c_cl = clp->c_cs;
444 }
445 }
446 out:
447 return count;
448 }
449
450 static int cc;
451
452 /*
453 * Given a non-NULL pointer into the clist return the pointer
454 * to the next 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 u_char *
461 nextc(struct clist *clp, u_char *cp, int *c)
462 {
463 if (clp->c_cf == cp) {
464 /*
465 * First time initialization.
466 */
467 cc = clp->c_cc;
468 }
469 if (cc == 0 || cp == NULL) {
470 return NULL;
471 }
472 if (--cc == 0) {
473 return NULL;
474 }
475 if (++cp == clp->c_ce) {
476 cp = clp->c_cs;
477 }
478 *c = *cp & 0xff;
479 if (clp->c_cq) {
480 #ifdef QBITS
481 if (isset(clp->c_cq, cp - clp->c_cs)) {
482 *c |= TTY_QUOTE;
483 }
484 #else
485 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
486 *c |= TTY_QUOTE;
487 }
488 #endif
489 }
490 return cp;
491 }
492
493 /*
494 * Given a non-NULL pointer into the clist return the pointer
495 * to the first character in the list or return NULL if no more chars.
496 *
497 * Callers must not allow getc's to happen between firstc's and getc's
498 * so that the pointer becomes invalid. Note that interrupts are NOT
499 * masked.
500 *
501 * *c is set to the NEXT character
502 */
503 u_char *
504 firstc(struct clist *clp, int *c)
505 {
506 u_char *cp;
507
508 cc = clp->c_cc;
509 if (cc == 0) {
510 return NULL;
511 }
512 cp = clp->c_cf;
513 *c = *cp & 0xff;
514 if (clp->c_cq) {
515 #ifdef QBITS
516 if (isset(clp->c_cq, cp - clp->c_cs)) {
517 *c |= TTY_QUOTE;
518 }
519 #else
520 if (*(cp - clp->c_cs + clp->c_cq)) {
521 *c |= TTY_QUOTE;
522 }
523 #endif
524 }
525 return clp->c_cf;
526 }
527
528 /*
529 * Remove the last character in the clist and return it.
530 */
531 int
532 unputc(struct clist *clp)
533 {
534 unsigned int c = -1;
535
536 if (clp->c_cc == 0) {
537 goto out;
538 }
539
540 if (clp->c_cl == clp->c_cs) {
541 clp->c_cl = clp->c_ce - 1;
542 } else {
543 --clp->c_cl;
544 }
545 clp->c_cc--;
546
547 c = *clp->c_cl & 0xff;
548 if (clp->c_cq) {
549 #ifdef QBITS
550 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) {
551 c |= TTY_QUOTE;
552 }
553 #else
554 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
555 c |= TTY_QUOTE;
556 }
557 #endif
558 }
559 if (clp->c_cc == 0) {
560 clp->c_cf = clp->c_cl = (u_char *)0;
561 }
562 out:
563 return c;
564 }
565
566 /*
567 * Put the chars in the from queue on the end of the to queue.
568 */
569 void
570 catq(struct clist *from, struct clist *to)
571 {
572 int c;
573
574 while ((c = getc(from)) != -1) {
575 putc(c, to);
576 }
577 }