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