]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/tty_subr.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / bsd / kern / tty_subr.c
... / ...
CommitLineData
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 */
94void
95cinit(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 */
103int
104clalloc(struct clist *clp, int size, int quot)
105{
106 MALLOC_ZONE(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
107 if (!clp->c_cs) {
108 return -1;
109 }
110 bzero(clp->c_cs, size);
111
112 if (quot) {
113 MALLOC_ZONE(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
114 if (!clp->c_cq) {
115 FREE_ZONE(clp->c_cs, size, M_TTYS);
116 return -1;
117 }
118 bzero(clp->c_cs, QMEM(size));
119 } else {
120 clp->c_cq = (u_char *)0;
121 }
122
123 clp->c_cf = clp->c_cl = (u_char *)0;
124 clp->c_ce = clp->c_cs + size;
125 clp->c_cn = size;
126 clp->c_cc = 0;
127 return 0;
128}
129
130void
131clfree(struct clist *clp)
132{
133 if (clp->c_cs) {
134 FREE_ZONE(clp->c_cs, clp->c_cn, M_TTYS);
135 }
136 if (clp->c_cq) {
137 FREE_ZONE(clp->c_cq, QMEM(clp->c_cn), M_TTYS);
138 }
139 clp->c_cs = clp->c_cq = (u_char *)0;
140}
141
142
143/*
144 * Get a character from a clist.
145 */
146int
147getc(struct clist *clp)
148{
149 int c = -1;
150
151 if (clp->c_cc == 0) {
152 goto out;
153 }
154
155 c = *clp->c_cf & 0xff;
156 if (clp->c_cq) {
157#ifdef QBITS
158 if (isset(clp->c_cq, clp->c_cf - clp->c_cs)) {
159 c |= TTY_QUOTE;
160 }
161#else
162 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
163 c |= TTY_QUOTE;
164 }
165#endif
166 }
167 if (++clp->c_cf == clp->c_ce) {
168 clp->c_cf = clp->c_cs;
169 }
170 if (--clp->c_cc == 0) {
171 clp->c_cf = clp->c_cl = (u_char *)0;
172 }
173out:
174 return c;
175}
176
177/*
178 * Copy clist to buffer.
179 * Return number of bytes moved.
180 */
181int
182q_to_b(struct clist *clp, u_char *cp, int count)
183{
184 int cc;
185 u_char *p = cp;
186
187 /* optimize this while loop */
188 while (count > 0 && clp->c_cc > 0) {
189 cc = clp->c_cl - clp->c_cf;
190 if (clp->c_cf >= clp->c_cl) {
191 cc = clp->c_ce - clp->c_cf;
192 }
193 if (cc > count) {
194 cc = count;
195 }
196 bcopy(clp->c_cf, p, cc);
197 count -= cc;
198 p += cc;
199 clp->c_cc -= cc;
200 clp->c_cf += cc;
201 if (clp->c_cf == clp->c_ce) {
202 clp->c_cf = clp->c_cs;
203 }
204 }
205 if (clp->c_cc == 0) {
206 clp->c_cf = clp->c_cl = (u_char *)0;
207 }
208 return p - cp;
209}
210
211/*
212 * Return count of contiguous characters in clist.
213 * Stop counting if flag&character is non-null.
214 */
215int
216ndqb(struct clist *clp, int flag)
217{
218 int count = 0;
219 int i;
220 int cc;
221
222 if ((cc = clp->c_cc) == 0) {
223 goto out;
224 }
225
226 if (flag == 0) {
227 count = clp->c_cl - clp->c_cf;
228 if (count <= 0) {
229 count = clp->c_ce - clp->c_cf;
230 }
231 goto out;
232 }
233
234 i = clp->c_cf - clp->c_cs;
235 if (flag & TTY_QUOTE) {
236 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
237 isset(clp->c_cq, i))) {
238 count++;
239 if (i == clp->c_cn) {
240 break;
241 }
242 }
243 } else {
244 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
245 count++;
246 if (i == clp->c_cn) {
247 break;
248 }
249 }
250 }
251out:
252 return count;
253}
254
255/*
256 * Flush count bytes from clist.
257 */
258void
259ndflush(struct clist *clp, int count)
260{
261 int cc;
262
263 if (count == clp->c_cc) {
264 clp->c_cc = 0;
265 clp->c_cf = clp->c_cl = (u_char *)0;
266 return;
267 }
268 /* optimize this while loop */
269 while (count > 0 && clp->c_cc > 0) {
270 cc = clp->c_cl - clp->c_cf;
271 if (clp->c_cf >= clp->c_cl) {
272 cc = clp->c_ce - clp->c_cf;
273 }
274 if (cc > count) {
275 cc = count;
276 }
277 count -= cc;
278 clp->c_cc -= cc;
279 clp->c_cf += cc;
280 if (clp->c_cf == clp->c_ce) {
281 clp->c_cf = clp->c_cs;
282 }
283 }
284 if (clp->c_cc == 0) {
285 clp->c_cf = clp->c_cl = (u_char *)0;
286 }
287}
288
289/*
290 * Put a character into the output queue.
291 */
292int
293putc(int c, struct clist *clp)
294{
295 int i;
296
297 if (clp->c_cc == 0) {
298 if (!clp->c_cs) {
299#if DIAGNOSTIC
300 //printf("putc: required clalloc\n");
301#endif
302 if (clalloc(clp, 1024, 1)) {
303out:
304 return -1;
305 }
306 }
307 clp->c_cf = clp->c_cl = clp->c_cs;
308 }
309
310 if (clp->c_cc == clp->c_cn) {
311 goto out;
312 }
313
314 *clp->c_cl = c & 0xff;
315 i = clp->c_cl - clp->c_cs;
316 if (clp->c_cq) {
317#ifdef QBITS
318 if (c & TTY_QUOTE) {
319 setbit(clp->c_cq, i);
320 } else {
321 clrbit(clp->c_cq, i);
322 }
323#else
324 q = clp->c_cq + i;
325 *q = (c & TTY_QUOTE) ? 1 : 0;
326#endif
327 }
328 clp->c_cc++;
329 clp->c_cl++;
330 if (clp->c_cl == clp->c_ce) {
331 clp->c_cl = clp->c_cs;
332 }
333 return 0;
334}
335
336#ifdef QBITS
337/*
338 * optimized version of
339 *
340 * for (i = 0; i < len; i++)
341 * clrbit(cp, off + len);
342 */
343void
344clrbits(u_char *cp, int off, int len)
345{
346 int sby, sbi, eby, ebi;
347 int i;
348 u_char mask;
349
350 if (len == 1) {
351 clrbit(cp, off);
352 return;
353 }
354
355 sby = off / NBBY;
356 sbi = off % NBBY;
357 eby = (off + len) / NBBY;
358 ebi = (off + len) % NBBY;
359 if (sby == eby) {
360 mask = ((1 << (ebi - sbi)) - 1) << sbi;
361 cp[sby] &= ~mask;
362 } else {
363 mask = (1 << sbi) - 1;
364 cp[sby++] &= mask;
365
366 mask = (1 << ebi) - 1;
367 /* handle remainder bits, if any, for a non-0 ebi value */
368 if (mask) {
369 cp[eby] &= ~mask;
370 }
371
372 for (i = sby; i < eby; i++) {
373 cp[i] = 0x00;
374 }
375 }
376}
377#endif
378
379/*
380 * Copy buffer to clist.
381 * Return number of bytes not transfered.
382 */
383int
384b_to_q(const u_char *cp, int count, struct clist *clp)
385{
386 int cc;
387 const u_char *p = cp;
388
389 if (count <= 0) {
390 return 0;
391 }
392
393
394 if (clp->c_cc == 0) {
395 if (!clp->c_cs) {
396#if DIAGNOSTIC
397 printf("b_to_q: required clalloc\n");
398#endif
399 if (clalloc(clp, 1024, 1)) {
400 goto out;
401 }
402 }
403 clp->c_cf = clp->c_cl = clp->c_cs;
404 }
405
406 if (clp->c_cc == clp->c_cn) {
407 goto out;
408 }
409
410 /* optimize this while loop */
411 while (count > 0 && clp->c_cc < clp->c_cn) {
412 cc = clp->c_ce - clp->c_cl;
413 if (clp->c_cf > clp->c_cl) {
414 cc = clp->c_cf - clp->c_cl;
415 }
416 if (cc > count) {
417 cc = count;
418 }
419 bcopy(p, clp->c_cl, cc);
420 if (clp->c_cq) {
421#ifdef QBITS
422 clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
423#else
424 bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
425#endif
426 }
427 p += cc;
428 count -= cc;
429 clp->c_cc += cc;
430 clp->c_cl += cc;
431 if (clp->c_cl == clp->c_ce) {
432 clp->c_cl = clp->c_cs;
433 }
434 }
435out:
436 return count;
437}
438
439static int cc;
440
441/*
442 * Given a non-NULL pointer into the clist return the pointer
443 * to the next character in the list or return NULL if no more chars.
444 *
445 * Callers must not allow getc's to happen between firstc's and getc's
446 * so that the pointer becomes invalid. Note that interrupts are NOT
447 * masked.
448 */
449u_char *
450nextc(struct clist *clp, u_char *cp, int *c)
451{
452 if (clp->c_cf == cp) {
453 /*
454 * First time initialization.
455 */
456 cc = clp->c_cc;
457 }
458 if (cc == 0 || cp == NULL) {
459 return NULL;
460 }
461 if (--cc == 0) {
462 return NULL;
463 }
464 if (++cp == clp->c_ce) {
465 cp = clp->c_cs;
466 }
467 *c = *cp & 0xff;
468 if (clp->c_cq) {
469#ifdef QBITS
470 if (isset(clp->c_cq, cp - clp->c_cs)) {
471 *c |= TTY_QUOTE;
472 }
473#else
474 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
475 *c |= TTY_QUOTE;
476 }
477#endif
478 }
479 return cp;
480}
481
482/*
483 * Given a non-NULL pointer into the clist return the pointer
484 * to the first character in the list or return NULL if no more chars.
485 *
486 * Callers must not allow getc's to happen between firstc's and getc's
487 * so that the pointer becomes invalid. Note that interrupts are NOT
488 * masked.
489 *
490 * *c is set to the NEXT character
491 */
492u_char *
493firstc(struct clist *clp, int *c)
494{
495 u_char *cp;
496
497 cc = clp->c_cc;
498 if (cc == 0) {
499 return NULL;
500 }
501 cp = clp->c_cf;
502 *c = *cp & 0xff;
503 if (clp->c_cq) {
504#ifdef QBITS
505 if (isset(clp->c_cq, cp - clp->c_cs)) {
506 *c |= TTY_QUOTE;
507 }
508#else
509 if (*(cp - clp->c_cs + clp->c_cq)) {
510 *c |= TTY_QUOTE;
511 }
512#endif
513 }
514 return clp->c_cf;
515}
516
517/*
518 * Remove the last character in the clist and return it.
519 */
520int
521unputc(struct clist *clp)
522{
523 unsigned int c = -1;
524
525 if (clp->c_cc == 0) {
526 goto out;
527 }
528
529 if (clp->c_cl == clp->c_cs) {
530 clp->c_cl = clp->c_ce - 1;
531 } else {
532 --clp->c_cl;
533 }
534 clp->c_cc--;
535
536 c = *clp->c_cl & 0xff;
537 if (clp->c_cq) {
538#ifdef QBITS
539 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) {
540 c |= TTY_QUOTE;
541 }
542#else
543 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
544 c |= TTY_QUOTE;
545 }
546#endif
547 }
548 if (clp->c_cc == 0) {
549 clp->c_cf = clp->c_cl = (u_char *)0;
550 }
551out:
552 return c;
553}
554
555/*
556 * Put the chars in the from queue on the end of the to queue.
557 */
558void
559catq(struct clist *from, struct clist *to)
560{
561 int c;
562
563 while ((c = getc(from)) != -1) {
564 putc(c, to);
565 }
566}