]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/tty_subr.c
xnu-6153.11.26.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{
0b4e3aa0 106 MALLOC_ZONE(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
0a7de745
A
107 if (!clp->c_cs) {
108 return -1;
109 }
1c79356b
A
110 bzero(clp->c_cs, size);
111
0a7de745 112 if (quot) {
0b4e3aa0 113 MALLOC_ZONE(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
1c79356b 114 if (!clp->c_cq) {
0b4e3aa0 115 FREE_ZONE(clp->c_cs, size, M_TTYS);
0a7de745 116 return -1;
1c79356b
A
117 }
118 bzero(clp->c_cs, QMEM(size));
0a7de745 119 } else {
1c79356b 120 clp->c_cq = (u_char *)0;
0a7de745 121 }
1c79356b
A
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;
0a7de745 127 return 0;
1c79356b
A
128}
129
130void
2d21ac55 131clfree(struct clist *clp)
1c79356b 132{
0a7de745 133 if (clp->c_cs) {
0b4e3aa0 134 FREE_ZONE(clp->c_cs, clp->c_cn, M_TTYS);
0a7de745
A
135 }
136 if (clp->c_cq) {
0b4e3aa0 137 FREE_ZONE(clp->c_cq, QMEM(clp->c_cn), M_TTYS);
0a7de745 138 }
1c79356b
A
139 clp->c_cs = clp->c_cq = (u_char *)0;
140}
141
142
143/*
144 * Get a character from a clist.
145 */
146int
2d21ac55 147getc(struct clist *clp)
1c79356b 148{
2d21ac55 149 int c = -1;
1c79356b 150
0a7de745 151 if (clp->c_cc == 0) {
1c79356b 152 goto out;
0a7de745 153 }
1c79356b
A
154
155 c = *clp->c_cf & 0xff;
156 if (clp->c_cq) {
157#ifdef QBITS
0a7de745 158 if (isset(clp->c_cq, clp->c_cf - clp->c_cs)) {
1c79356b 159 c |= TTY_QUOTE;
0a7de745 160 }
1c79356b 161#else
0a7de745 162 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 163 c |= TTY_QUOTE;
0a7de745 164 }
1c79356b
A
165#endif
166 }
0a7de745 167 if (++clp->c_cf == clp->c_ce) {
1c79356b 168 clp->c_cf = clp->c_cs;
0a7de745
A
169 }
170 if (--clp->c_cc == 0) {
1c79356b 171 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 172 }
1c79356b 173out:
1c79356b
A
174 return c;
175}
176
177/*
178 * Copy clist to buffer.
179 * Return number of bytes moved.
180 */
181int
2d21ac55 182q_to_b(struct clist *clp, u_char *cp, int count)
1c79356b 183{
2d21ac55 184 int cc;
1c79356b 185 u_char *p = cp;
1c79356b 186
1c79356b
A
187 /* optimize this while loop */
188 while (count > 0 && clp->c_cc > 0) {
189 cc = clp->c_cl - clp->c_cf;
0a7de745 190 if (clp->c_cf >= clp->c_cl) {
1c79356b 191 cc = clp->c_ce - clp->c_cf;
0a7de745
A
192 }
193 if (cc > count) {
1c79356b 194 cc = count;
0a7de745 195 }
1c79356b
A
196 bcopy(clp->c_cf, p, cc);
197 count -= cc;
198 p += cc;
199 clp->c_cc -= cc;
200 clp->c_cf += cc;
0a7de745 201 if (clp->c_cf == clp->c_ce) {
1c79356b 202 clp->c_cf = clp->c_cs;
0a7de745 203 }
1c79356b 204 }
0a7de745 205 if (clp->c_cc == 0) {
1c79356b 206 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 207 }
1c79356b
A
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
2d21ac55 216ndqb(struct clist *clp, int flag)
1c79356b
A
217{
218 int count = 0;
39037602
A
219 int i;
220 int cc;
1c79356b 221
0a7de745 222 if ((cc = clp->c_cc) == 0) {
1c79356b 223 goto out;
0a7de745 224 }
1c79356b
A
225
226 if (flag == 0) {
227 count = clp->c_cl - clp->c_cf;
0a7de745 228 if (count <= 0) {
1c79356b 229 count = clp->c_ce - clp->c_cf;
0a7de745 230 }
1c79356b
A
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++;
0a7de745 239 if (i == clp->c_cn) {
1c79356b 240 break;
0a7de745 241 }
1c79356b
A
242 }
243 } else {
244 while (cc-- > 0 && !(clp->c_cs[i++] & flag)) {
245 count++;
0a7de745 246 if (i == clp->c_cn) {
1c79356b 247 break;
0a7de745 248 }
1c79356b
A
249 }
250 }
251out:
1c79356b
A
252 return count;
253}
254
255/*
256 * Flush count bytes from clist.
257 */
258void
2d21ac55 259ndflush(struct clist *clp, int count)
1c79356b 260{
2d21ac55 261 int cc;
1c79356b 262
1c79356b
A
263 if (count == clp->c_cc) {
264 clp->c_cc = 0;
265 clp->c_cf = clp->c_cl = (u_char *)0;
2d21ac55 266 return;
1c79356b
A
267 }
268 /* optimize this while loop */
269 while (count > 0 && clp->c_cc > 0) {
270 cc = clp->c_cl - clp->c_cf;
0a7de745 271 if (clp->c_cf >= clp->c_cl) {
1c79356b 272 cc = clp->c_ce - clp->c_cf;
0a7de745
A
273 }
274 if (cc > count) {
1c79356b 275 cc = count;
0a7de745 276 }
1c79356b
A
277 count -= cc;
278 clp->c_cc -= cc;
279 clp->c_cf += cc;
0a7de745 280 if (clp->c_cf == clp->c_ce) {
1c79356b 281 clp->c_cf = clp->c_cs;
0a7de745 282 }
1c79356b 283 }
0a7de745 284 if (clp->c_cc == 0) {
1c79356b 285 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 286 }
1c79356b
A
287}
288
289/*
290 * Put a character into the output queue.
291 */
292int
2d21ac55 293putc(int c, struct clist *clp)
1c79356b 294{
39037602 295 int i;
1c79356b 296
1c79356b
A
297 if (clp->c_cc == 0) {
298 if (!clp->c_cs) {
299#if DIAGNOSTIC
300 //printf("putc: required clalloc\n");
301#endif
0a7de745 302 if (clalloc(clp, 1024, 1)) {
1c79356b 303out:
1c79356b
A
304 return -1;
305 }
306 }
307 clp->c_cf = clp->c_cl = clp->c_cs;
308 }
309
0a7de745 310 if (clp->c_cc == clp->c_cn) {
1c79356b 311 goto out;
0a7de745 312 }
1c79356b
A
313
314 *clp->c_cl = c & 0xff;
315 i = clp->c_cl - clp->c_cs;
316 if (clp->c_cq) {
317#ifdef QBITS
0a7de745
A
318 if (c & TTY_QUOTE) {
319 setbit(clp->c_cq, i);
320 } else {
1c79356b 321 clrbit(clp->c_cq, i);
0a7de745 322 }
1c79356b
A
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++;
0a7de745 330 if (clp->c_cl == clp->c_ce) {
1c79356b 331 clp->c_cl = clp->c_cs;
0a7de745 332 }
1c79356b
A
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
91447636 344clrbits(u_char *cp, int off, int len)
1c79356b
A
345{
346 int sby, sbi, eby, ebi;
39037602 347 int i;
1c79356b
A
348 u_char mask;
349
0a7de745 350 if (len == 1) {
1c79356b
A
351 clrbit(cp, off);
352 return;
353 }
354
355 sby = off / NBBY;
356 sbi = off % NBBY;
0a7de745
A
357 eby = (off + len) / NBBY;
358 ebi = (off + len) % NBBY;
1c79356b
A
359 if (sby == eby) {
360 mask = ((1 << (ebi - sbi)) - 1) << sbi;
361 cp[sby] &= ~mask;
362 } else {
0a7de745 363 mask = (1 << sbi) - 1;
1c79356b
A
364 cp[sby++] &= mask;
365
0a7de745 366 mask = (1 << ebi) - 1;
6d2010ae 367 /* handle remainder bits, if any, for a non-0 ebi value */
0a7de745 368 if (mask) {
6d2010ae 369 cp[eby] &= ~mask;
0a7de745 370 }
1c79356b 371
0a7de745 372 for (i = sby; i < eby; i++) {
1c79356b 373 cp[i] = 0x00;
0a7de745 374 }
1c79356b
A
375 }
376}
377#endif
378
379/*
380 * Copy buffer to clist.
381 * Return number of bytes not transfered.
382 */
383int
91447636 384b_to_q(const u_char *cp, int count, struct clist *clp)
1c79356b 385{
91447636
A
386 int cc;
387 const u_char *p = cp;
1c79356b 388
0a7de745 389 if (count <= 0) {
1c79356b 390 return 0;
0a7de745 391 }
1c79356b 392
1c79356b
A
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
0a7de745 399 if (clalloc(clp, 1024, 1)) {
1c79356b 400 goto out;
0a7de745 401 }
1c79356b
A
402 }
403 clp->c_cf = clp->c_cl = clp->c_cs;
404 }
405
0a7de745 406 if (clp->c_cc == clp->c_cn) {
1c79356b 407 goto out;
0a7de745 408 }
1c79356b
A
409
410 /* optimize this while loop */
411 while (count > 0 && clp->c_cc < clp->c_cn) {
412 cc = clp->c_ce - clp->c_cl;
0a7de745 413 if (clp->c_cf > clp->c_cl) {
1c79356b 414 cc = clp->c_cf - clp->c_cl;
0a7de745
A
415 }
416 if (cc > count) {
1c79356b 417 cc = count;
0a7de745 418 }
1c79356b
A
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;
0a7de745 431 if (clp->c_cl == clp->c_ce) {
1c79356b 432 clp->c_cl = clp->c_cs;
0a7de745 433 }
1c79356b
A
434 }
435out:
1c79356b
A
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 *
2d21ac55 450nextc(struct clist *clp, u_char *cp, int *c)
1c79356b 451{
1c79356b
A
452 if (clp->c_cf == cp) {
453 /*
454 * First time initialization.
455 */
456 cc = clp->c_cc;
457 }
0a7de745 458 if (cc == 0 || cp == NULL) {
1c79356b 459 return NULL;
0a7de745
A
460 }
461 if (--cc == 0) {
1c79356b 462 return NULL;
0a7de745
A
463 }
464 if (++cp == clp->c_ce) {
1c79356b 465 cp = clp->c_cs;
0a7de745 466 }
1c79356b
A
467 *c = *cp & 0xff;
468 if (clp->c_cq) {
469#ifdef QBITS
0a7de745 470 if (isset(clp->c_cq, cp - clp->c_cs)) {
1c79356b 471 *c |= TTY_QUOTE;
0a7de745 472 }
1c79356b 473#else
0a7de745 474 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 475 *c |= TTY_QUOTE;
0a7de745 476 }
1c79356b
A
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 *
2d21ac55 493firstc(struct clist *clp, int *c)
1c79356b 494{
2d21ac55 495 u_char *cp;
1c79356b
A
496
497 cc = clp->c_cc;
0a7de745 498 if (cc == 0) {
1c79356b 499 return NULL;
0a7de745 500 }
1c79356b
A
501 cp = clp->c_cf;
502 *c = *cp & 0xff;
0a7de745 503 if (clp->c_cq) {
1c79356b 504#ifdef QBITS
0a7de745 505 if (isset(clp->c_cq, cp - clp->c_cs)) {
1c79356b 506 *c |= TTY_QUOTE;
0a7de745 507 }
1c79356b 508#else
0a7de745 509 if (*(cp - clp->c_cs + clp->c_cq)) {
1c79356b 510 *c |= TTY_QUOTE;
0a7de745 511 }
1c79356b
A
512#endif
513 }
514 return clp->c_cf;
515}
516
517/*
518 * Remove the last character in the clist and return it.
519 */
520int
2d21ac55 521unputc(struct clist *clp)
1c79356b
A
522{
523 unsigned int c = -1;
1c79356b 524
0a7de745 525 if (clp->c_cc == 0) {
1c79356b 526 goto out;
0a7de745 527 }
1c79356b 528
0a7de745 529 if (clp->c_cl == clp->c_cs) {
1c79356b 530 clp->c_cl = clp->c_ce - 1;
0a7de745 531 } else {
1c79356b 532 --clp->c_cl;
0a7de745 533 }
1c79356b
A
534 clp->c_cc--;
535
536 c = *clp->c_cl & 0xff;
537 if (clp->c_cq) {
538#ifdef QBITS
0a7de745 539 if (isset(clp->c_cq, clp->c_cl - clp->c_cs)) {
1c79356b 540 c |= TTY_QUOTE;
0a7de745 541 }
1c79356b 542#else
0a7de745 543 if (*(clp->c_cf - clp->c_cs + clp->c_cq)) {
1c79356b 544 c |= TTY_QUOTE;
0a7de745 545 }
1c79356b
A
546#endif
547 }
0a7de745 548 if (clp->c_cc == 0) {
1c79356b 549 clp->c_cf = clp->c_cl = (u_char *)0;
0a7de745 550 }
1c79356b 551out:
1c79356b
A
552 return c;
553}
554
555/*
556 * Put the chars in the from queue on the end of the to queue.
557 */
558void
2d21ac55 559catq(struct clist *from, struct clist *to)
1c79356b
A
560{
561 int c;
562
0a7de745 563 while ((c = getc(from)) != -1) {
1c79356b 564 putc(c, to);
0a7de745 565 }
1c79356b 566}