]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_subr.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / tty_subr.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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
1c79356b
A
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>
1c79356b
A
64#include <sys/ioctl.h>
65#include <sys/tty.h>
66#include <sys/malloc.h>
67
1c79356b
A
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.
0a7de745 75 *
1c79356b
A
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
0a7de745 85#define QMEM(n) ((((n)-1)/NBBY)+1)
1c79356b 86#else
0a7de745 87#define QMEM(n) (n)
1c79356b
A
88#endif
89
90
91/*
92 * Initialize clists.
93 */
94void
91447636 95cinit(void)
1c79356b
A
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
2d21ac55 104clalloc(struct clist *clp, int size, int quot)
1c79356b 105{
f427ee49 106 clp->c_cs = kheap_alloc(KHEAP_DATA_BUFFERS, size, Z_WAITOK | Z_ZERO);
0a7de745
A
107 if (!clp->c_cs) {
108 return -1;
109 }
1c79356b 110
0a7de745 111 if (quot) {
f427ee49
A
112 clp->c_cq = kheap_alloc(KHEAP_DATA_BUFFERS,
113 QMEM(size), Z_WAITOK | Z_ZERO);
1c79356b 114 if (!clp->c_cq) {
f427ee49 115 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cs, size);
0a7de745 116 return -1;
1c79356b 117 }
0a7de745 118 } else {
1c79356b 119 clp->c_cq = (u_char *)0;
0a7de745 120 }
1c79356b
A
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;
0a7de745 126 return 0;
1c79356b
A
127}
128
129void
2d21ac55 130clfree(struct clist *clp)
1c79356b 131{
0a7de745 132 if (clp->c_cs) {
f427ee49 133 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cs, clp->c_cn);
0a7de745
A
134 }
135 if (clp->c_cq) {
f427ee49 136 kheap_free(KHEAP_DATA_BUFFERS, clp->c_cq, QMEM(clp->c_cn));
0a7de745 137 }
1c79356b
A
138 clp->c_cs = clp->c_cq = (u_char *)0;
139}
140
141
142/*
143 * Get a character from a clist.
144 */
145int
2d21ac55 146getc(struct clist *clp)
1c79356b 147{
2d21ac55 148 int c = -1;
1c79356b 149
0a7de745 150 if (clp->c_cc == 0) {
1c79356b 151 goto out;
0a7de745 152 }
1c79356b
A
153
154 c = *clp->c_cf & 0xff;
155 if (clp->c_cq) {
156#ifdef QBITS
0a7de745 157 if (isset(clp->c_cq, clp->c_cf - clp->c_cs)) {
1c79356b 158 c |= TTY_QUOTE;
0a7de745 159 }
1c79356b 160#else
0a7de745 161 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 162 c |= TTY_QUOTE;
0a7de745 163 }
1c79356b
A
164#endif
165 }
0a7de745 166 if (++clp->c_cf == clp->c_ce) {
1c79356b 167 clp->c_cf = clp->c_cs;
0a7de745
A
168 }
169 if (--clp->c_cc == 0) {
1c79356b 170 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 171 }
1c79356b 172out:
1c79356b
A
173 return c;
174}
175
176/*
177 * Copy clist to buffer.
178 * Return number of bytes moved.
179 */
180int
2d21ac55 181q_to_b(struct clist *clp, u_char *cp, int count)
1c79356b 182{
f427ee49 183 size_t cc;
1c79356b 184 u_char *p = cp;
1c79356b 185
1c79356b
A
186 /* optimize this while loop */
187 while (count > 0 && clp->c_cc > 0) {
188 cc = clp->c_cl - clp->c_cf;
0a7de745 189 if (clp->c_cf >= clp->c_cl) {
1c79356b 190 cc = clp->c_ce - clp->c_cf;
0a7de745 191 }
f427ee49 192 if (cc > INT_MAX || (int)cc > count) {
1c79356b 193 cc = count;
0a7de745 194 }
1c79356b
A
195 bcopy(clp->c_cf, p, cc);
196 count -= cc;
197 p += cc;
198 clp->c_cc -= cc;
199 clp->c_cf += cc;
0a7de745 200 if (clp->c_cf == clp->c_ce) {
1c79356b 201 clp->c_cf = clp->c_cs;
0a7de745 202 }
1c79356b 203 }
0a7de745 204 if (clp->c_cc == 0) {
1c79356b 205 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 206 }
f427ee49 207 return (int)MIN(INT32_MAX, p - cp);
1c79356b
A
208}
209
210/*
211 * Return count of contiguous characters in clist.
212 * Stop counting if flag&character is non-null.
213 */
214int
2d21ac55 215ndqb(struct clist *clp, int flag)
1c79356b 216{
f427ee49
A
217 size_t count = 0;
218 size_t i;
39037602 219 int cc;
1c79356b 220
0a7de745 221 if ((cc = clp->c_cc) == 0) {
1c79356b 222 goto out;
0a7de745 223 }
1c79356b
A
224
225 if (flag == 0) {
226 count = clp->c_cl - clp->c_cf;
0a7de745 227 if (count <= 0) {
1c79356b 228 count = clp->c_ce - clp->c_cf;
0a7de745 229 }
1c79356b
A
230 goto out;
231 }
232
233 i = clp->c_cf - clp->c_cs;
f427ee49
A
234 if (i > INT_MAX) {
235 return 0;
236 }
1c79356b
A
237 if (flag & TTY_QUOTE) {
238 while (cc-- > 0 && !(clp->c_cs[i++] & (flag & ~TTY_QUOTE) ||
239 isset(clp->c_cq, i))) {
240 count++;
f427ee49 241 if ((int)i == clp->c_cn) {
1c79356b 242 break;
0a7de745 243 }
1c79356b
A
244 }
245 } else {
246 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
247 count++;
f427ee49 248 if ((int)i == clp->c_cn) {
1c79356b 249 break;
0a7de745 250 }
1c79356b
A
251 }
252 }
253out:
f427ee49
A
254 if (count > INT_MAX) {
255 return 0;
256 }
257 return (int)count;
1c79356b
A
258}
259
260/*
261 * Flush count bytes from clist.
262 */
263void
2d21ac55 264ndflush(struct clist *clp, int count)
1c79356b 265{
f427ee49 266 size_t cc;
1c79356b 267
1c79356b
A
268 if (count == clp->c_cc) {
269 clp->c_cc = 0;
270 clp->c_cf = clp->c_cl = (u_char *)0;
2d21ac55 271 return;
1c79356b
A
272 }
273 /* optimize this while loop */
274 while (count > 0 && clp->c_cc > 0) {
275 cc = clp->c_cl - clp->c_cf;
0a7de745 276 if (clp->c_cf >= clp->c_cl) {
1c79356b 277 cc = clp->c_ce - clp->c_cf;
0a7de745 278 }
f427ee49 279 if (cc > INT_MAX || (int)cc > count) {
1c79356b 280 cc = count;
0a7de745 281 }
1c79356b
A
282 count -= cc;
283 clp->c_cc -= cc;
284 clp->c_cf += cc;
0a7de745 285 if (clp->c_cf == clp->c_ce) {
1c79356b 286 clp->c_cf = clp->c_cs;
0a7de745 287 }
1c79356b 288 }
0a7de745 289 if (clp->c_cc == 0) {
1c79356b 290 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 291 }
1c79356b
A
292}
293
294/*
295 * Put a character into the output queue.
296 */
297int
2d21ac55 298putc(int c, struct clist *clp)
1c79356b 299{
f427ee49 300 size_t i;
1c79356b 301
1c79356b
A
302 if (clp->c_cc == 0) {
303 if (!clp->c_cs) {
304#if DIAGNOSTIC
305 //printf("putc: required clalloc\n");
306#endif
0a7de745 307 if (clalloc(clp, 1024, 1)) {
1c79356b
A
308 return -1;
309 }
310 }
311 clp->c_cf = clp->c_cl = clp->c_cs;
312 }
313
0a7de745 314 if (clp->c_cc == clp->c_cn) {
f427ee49 315 return -1;
0a7de745 316 }
1c79356b
A
317
318 *clp->c_cl = c & 0xff;
319 i = clp->c_cl - clp->c_cs;
f427ee49
A
320 if (i > INT_MAX) {
321 return -1;
322 }
1c79356b
A
323 if (clp->c_cq) {
324#ifdef QBITS
0a7de745
A
325 if (c & TTY_QUOTE) {
326 setbit(clp->c_cq, i);
327 } else {
1c79356b 328 clrbit(clp->c_cq, i);
0a7de745 329 }
1c79356b
A
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++;
0a7de745 337 if (clp->c_cl == clp->c_ce) {
1c79356b 338 clp->c_cl = clp->c_cs;
0a7de745 339 }
1c79356b
A
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 */
350void
91447636 351clrbits(u_char *cp, int off, int len)
1c79356b
A
352{
353 int sby, sbi, eby, ebi;
39037602 354 int i;
1c79356b
A
355 u_char mask;
356
0a7de745 357 if (len == 1) {
1c79356b
A
358 clrbit(cp, off);
359 return;
360 }
361
362 sby = off / NBBY;
363 sbi = off % NBBY;
0a7de745
A
364 eby = (off + len) / NBBY;
365 ebi = (off + len) % NBBY;
1c79356b 366 if (sby == eby) {
f427ee49 367 mask = (u_char)(((1 << (ebi - sbi)) - 1) << sbi);
1c79356b
A
368 cp[sby] &= ~mask;
369 } else {
f427ee49 370 mask = (u_char)((1 << sbi) - 1);
1c79356b
A
371 cp[sby++] &= mask;
372
f427ee49 373 mask = (u_char)((1 << ebi) - 1);
6d2010ae 374 /* handle remainder bits, if any, for a non-0 ebi value */
0a7de745 375 if (mask) {
6d2010ae 376 cp[eby] &= ~mask;
0a7de745 377 }
1c79356b 378
0a7de745 379 for (i = sby; i < eby; i++) {
1c79356b 380 cp[i] = 0x00;
0a7de745 381 }
1c79356b
A
382 }
383}
384#endif
385
386/*
387 * Copy buffer to clist.
388 * Return number of bytes not transfered.
389 */
390int
91447636 391b_to_q(const u_char *cp, int count, struct clist *clp)
1c79356b 392{
f427ee49 393 size_t cc;
91447636 394 const u_char *p = cp;
1c79356b 395
0a7de745 396 if (count <= 0) {
1c79356b 397 return 0;
0a7de745 398 }
1c79356b 399
1c79356b
A
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
0a7de745 406 if (clalloc(clp, 1024, 1)) {
1c79356b 407 goto out;
0a7de745 408 }
1c79356b
A
409 }
410 clp->c_cf = clp->c_cl = clp->c_cs;
411 }
412
0a7de745 413 if (clp->c_cc == clp->c_cn) {
1c79356b 414 goto out;
0a7de745 415 }
1c79356b
A
416
417 /* optimize this while loop */
418 while (count > 0 && clp->c_cc < clp->c_cn) {
419 cc = clp->c_ce - clp->c_cl;
0a7de745 420 if (clp->c_cf > clp->c_cl) {
1c79356b 421 cc = clp->c_cf - clp->c_cl;
0a7de745 422 }
f427ee49 423 if (cc > INT_MAX || (int)cc > count) {
1c79356b 424 cc = count;
0a7de745 425 }
1c79356b
A
426 bcopy(p, clp->c_cl, cc);
427 if (clp->c_cq) {
428#ifdef QBITS
f427ee49
A
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);
1c79356b
A
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;
0a7de745 442 if (clp->c_cl == clp->c_ce) {
1c79356b 443 clp->c_cl = clp->c_cs;
0a7de745 444 }
1c79356b
A
445 }
446out:
1c79356b
A
447 return count;
448}
449
450static 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 */
460u_char *
2d21ac55 461nextc(struct clist *clp, u_char *cp, int *c)
1c79356b 462{
1c79356b
A
463 if (clp->c_cf == cp) {
464 /*
465 * First time initialization.
466 */
467 cc = clp->c_cc;
468 }
0a7de745 469 if (cc == 0 || cp == NULL) {
1c79356b 470 return NULL;
0a7de745
A
471 }
472 if (--cc == 0) {
1c79356b 473 return NULL;
0a7de745
A
474 }
475 if (++cp == clp->c_ce) {
1c79356b 476 cp = clp->c_cs;
0a7de745 477 }
1c79356b
A
478 *c = *cp & 0xff;
479 if (clp->c_cq) {
480#ifdef QBITS
0a7de745 481 if (isset(clp->c_cq, cp - clp->c_cs)) {
1c79356b 482 *c |= TTY_QUOTE;
0a7de745 483 }
1c79356b 484#else
0a7de745 485 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 486 *c |= TTY_QUOTE;
0a7de745 487 }
1c79356b
A
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 */
503u_char *
2d21ac55 504firstc(struct clist *clp, int *c)
1c79356b 505{
2d21ac55 506 u_char *cp;
1c79356b
A
507
508 cc = clp->c_cc;
0a7de745 509 if (cc == 0) {
1c79356b 510 return NULL;
0a7de745 511 }
1c79356b
A
512 cp = clp->c_cf;
513 *c = *cp & 0xff;
0a7de745 514 if (clp->c_cq) {
1c79356b 515#ifdef QBITS
0a7de745 516 if (isset(clp->c_cq, cp - clp->c_cs)) {
1c79356b 517 *c |= TTY_QUOTE;
0a7de745 518 }
1c79356b 519#else
0a7de745 520 if (*(cp - clp->c_cs + clp->c_cq)) {
1c79356b 521 *c |= TTY_QUOTE;
0a7de745 522 }
1c79356b
A
523#endif
524 }
525 return clp->c_cf;
526}
527
528/*
529 * Remove the last character in the clist and return it.
530 */
531int
2d21ac55 532unputc(struct clist *clp)
1c79356b
A
533{
534 unsigned int c = -1;
1c79356b 535
0a7de745 536 if (clp->c_cc == 0) {
1c79356b 537 goto out;
0a7de745 538 }
1c79356b 539
0a7de745 540 if (clp->c_cl == clp->c_cs) {
1c79356b 541 clp->c_cl = clp->c_ce - 1;
0a7de745 542 } else {
1c79356b 543 --clp->c_cl;
0a7de745 544 }
1c79356b
A
545 clp->c_cc--;
546
547 c = *clp->c_cl & 0xff;
548 if (clp->c_cq) {
549#ifdef QBITS
0a7de745 550 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) {
1c79356b 551 c |= TTY_QUOTE;
0a7de745 552 }
1c79356b 553#else
0a7de745 554 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 555 c |= TTY_QUOTE;
0a7de745 556 }
1c79356b
A
557#endif
558 }
0a7de745 559 if (clp->c_cc == 0) {
1c79356b 560 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 561 }
1c79356b 562out:
1c79356b
A
563 return c;
564}
565
566/*
567 * Put the chars in the from queue on the end of the to queue.
568 */
569void
2d21ac55 570catq(struct clist *from, struct clist *to)
1c79356b
A
571{
572 int c;
573
0a7de745 574 while ((c = getc(from)) != -1) {
1c79356b 575 putc(c, to);
0a7de745 576 }
1c79356b 577}