1 /* $NetBSD: tty_subr.c,v 1.38 2009/11/13 19:15:24 dsl Exp $ */
4 * Copyright (c) 1993, 1994 Theo de Raadt
7 * Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
8 * set of true clist functions that this is very loosely based on.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: tty_subr.c,v 1.38 2009/11/13 19:15:24 dsl Exp $");
34 #include <sys/param.h>
35 #include <sys/systm.h>
37 #include <sys/ioctl.h>
42 * At compile time, choose:
43 * There are two ways the TTY_QUOTE bit can be stored. If QBITS is
44 * defined we allocate an array of bits -- 1/8th as much memory but
45 * setbit(), clrbit(), and isset() take more CPU. If QBITS is
46 * undefined, we just use an array of bytes.
48 * If TTY_QUOTE functionality isn't required by a line discipline,
49 * it can free c_cq and set it to NULL. This speeds things up,
50 * and also does not use any extra memory. This is useful for (say)
51 * a SLIP line discipline that wants a 32K ring buffer for data
52 * but doesn't need quoting.
57 #define QMEM(n) ((((n)-1)/NBBY)+1)
63 static void clrbits(u_char
*, unsigned int, unsigned int);
67 * Initialize a particular clist. Ok, they are really ring buffers,
68 * of the specified length, with/without quoting support.
71 clalloc(struct clist
*clp
, int size
, int quot
)
74 clp
->c_cs
= kmem_zalloc(size
, KM_SLEEP
);
79 clp
->c_cq
= kmem_zalloc(QMEM(size
), KM_SLEEP
);
81 kmem_free(clp
->c_cs
, size
);
87 clp
->c_cf
= clp
->c_cl
= NULL
;
88 clp
->c_ce
= clp
->c_cs
+ size
;
96 clfree(struct clist
*clp
)
99 kmem_free(clp
->c_cs
, clp
->c_cn
);
101 kmem_free(clp
->c_cq
, QMEM(clp
->c_cn
));
102 clp
->c_cs
= clp
->c_cq
= NULL
;
106 * Get a character from a clist.
109 getc(struct clist
*clp
)
118 c
= *clp
->c_cf
& 0xff;
121 if (isset(clp
->c_cq
, clp
->c_cf
- clp
->c_cs
) )
124 if (*(clp
->c_cf
- clp
->c_cs
+ clp
->c_cq
))
128 *clp
->c_cf
= 0; /* wipe out to avoid information disclosure */
129 if (++clp
->c_cf
== clp
->c_ce
)
130 clp
->c_cf
= clp
->c_cs
;
131 if (--clp
->c_cc
== 0)
132 clp
->c_cf
= clp
->c_cl
= (u_char
*)0;
139 * Copy clist to buffer.
140 * Return number of bytes moved.
143 q_to_b(struct clist
*clp
, u_char
*cp
, int count
)
150 /* optimize this while loop */
151 while (count
> 0 && clp
->c_cc
> 0) {
152 cc
= clp
->c_cl
- clp
->c_cf
;
153 if (clp
->c_cf
>= clp
->c_cl
)
154 cc
= clp
->c_ce
- clp
->c_cf
;
157 memcpy(p
, clp
->c_cf
, cc
);
162 if (clp
->c_cf
== clp
->c_ce
)
163 clp
->c_cf
= clp
->c_cs
;
166 clp
->c_cf
= clp
->c_cl
= (u_char
*)0;
172 * Return count of contiguous characters in clist.
173 * Stop counting if flag&character is non-null.
176 ndqb(struct clist
*clp
, int flag
)
184 if ((cc
= clp
->c_cc
) == 0)
188 count
= clp
->c_cl
- clp
->c_cf
;
190 count
= clp
->c_ce
- clp
->c_cf
;
194 i
= clp
->c_cf
- clp
->c_cs
;
195 if (flag
& TTY_QUOTE
) {
196 while (cc
-- > 0 && !(clp
->c_cs
[i
++] & (flag
& ~TTY_QUOTE
) ||
197 isset(clp
->c_cq
, i
))) {
203 while (cc
-- > 0 && !(clp
->c_cs
[i
++] & flag
)) {
215 * Flush count bytes from clist.
218 ndflush(struct clist
*clp
, int count
)
224 if (count
== clp
->c_cc
) {
226 clp
->c_cf
= clp
->c_cl
= (u_char
*)0;
229 /* optimize this while loop */
230 while (count
> 0 && clp
->c_cc
> 0) {
231 cc
= clp
->c_cl
- clp
->c_cf
;
232 if (clp
->c_cf
>= clp
->c_cl
)
233 cc
= clp
->c_ce
- clp
->c_cf
;
239 if (clp
->c_cf
== clp
->c_ce
)
240 clp
->c_cf
= clp
->c_cs
;
243 clp
->c_cf
= clp
->c_cl
= (u_char
*)0;
249 * Put a character into the output queue.
252 putc(int c
, struct clist
*clp
)
258 if (clp
->c_cc
== clp
->c_cn
)
261 if (clp
->c_cc
== 0) {
263 #if defined(DIAGNOSTIC) || 1
264 printf("putc: required clalloc\n");
266 if (clalloc(clp
, 1024, 1)) {
272 clp
->c_cf
= clp
->c_cl
= clp
->c_cs
;
275 *clp
->c_cl
= c
& 0xff;
276 i
= clp
->c_cl
- clp
->c_cs
;
280 setbit(clp
->c_cq
, i
);
282 clrbit(clp
->c_cq
, i
);
285 *q
= (c
& TTY_QUOTE
) ? 1 : 0;
290 if (clp
->c_cl
== clp
->c_ce
)
291 clp
->c_cl
= clp
->c_cs
;
298 * optimized version of
300 * for (i = 0; i < len; i++)
301 * clrbit(cp, off + len);
304 clrbits(u_char
*cp
, unsigned int off
, unsigned int len
)
306 unsigned int sbi
, ebi
;
311 scp
= cp
+ off
/ NBBY
;
313 end
= off
+ len
+ NBBY
- 1;
314 ecp
= cp
+ end
/ NBBY
- 1;
315 ebi
= end
% NBBY
+ 1;
317 mask
= ((1 << len
) - 1) << sbi
;
320 mask
= (1 << sbi
) - 1;
323 mask
= (1 << ebi
) - 1;
333 * Copy buffer to clist.
334 * Return number of bytes not transfered.
337 b_to_q(const u_char
*cp
, int count
, struct clist
*clp
)
340 const u_char
*p
= cp
;
347 if (clp
->c_cc
== clp
->c_cn
)
350 if (clp
->c_cc
== 0) {
352 #if defined(DIAGNOSTIC) || 1
353 printf("b_to_q: required clalloc\n");
355 if (clalloc(clp
, 1024, 1))
358 clp
->c_cf
= clp
->c_cl
= clp
->c_cs
;
361 /* optimize this while loop */
362 while (count
> 0 && clp
->c_cc
< clp
->c_cn
) {
363 cc
= clp
->c_ce
- clp
->c_cl
;
364 if (clp
->c_cf
> clp
->c_cl
)
365 cc
= clp
->c_cf
- clp
->c_cl
;
368 memcpy(clp
->c_cl
, p
, cc
);
371 clrbits(clp
->c_cq
, clp
->c_cl
- clp
->c_cs
, cc
);
373 memset(clp
->c_cl
- clp
->c_cs
+ clp
->c_cq
, 0, cc
);
380 if (clp
->c_cl
== clp
->c_ce
)
381 clp
->c_cl
= clp
->c_cs
;
391 * Given a non-NULL pointer into the clist return the pointer
392 * to the next character in the list or return NULL if no more chars.
394 * Callers must not allow getc's to happen between firstc's and getc's
395 * so that the pointer becomes invalid. Note that interrupts are NOT
399 nextc(struct clist
*clp
, u_char
*cp
, int *c
)
402 if (clp
->c_cf
== cp
) {
404 * First time initialization.
408 if (cc
== 0 || cp
== NULL
)
412 if (++cp
== clp
->c_ce
)
417 if (isset(clp
->c_cq
, cp
- clp
->c_cs
))
420 if (*(clp
->c_cf
- clp
->c_cs
+ clp
->c_cq
))
428 * Given a non-NULL pointer into the clist return the pointer
429 * to the first character in the list or return NULL if no more chars.
431 * Callers must not allow getc's to happen between firstc's and getc's
432 * so that the pointer becomes invalid. Note that interrupts are NOT
435 * *c is set to the NEXT character
438 firstc(struct clist
*clp
, int *c
)
449 if (isset(clp
->c_cq
, cp
- clp
->c_cs
))
452 if (*(cp
- clp
->c_cs
+ clp
->c_cq
))
460 * Remove the last character in the clist and return it.
463 unputc(struct clist
*clp
)
472 if (clp
->c_cl
== clp
->c_cs
)
473 clp
->c_cl
= clp
->c_ce
- 1;
478 c
= *clp
->c_cl
& 0xff;
481 if (isset(clp
->c_cq
, clp
->c_cl
- clp
->c_cs
))
484 if (*(clp
->c_cf
- clp
->c_cs
+ clp
->c_cq
))
489 clp
->c_cf
= clp
->c_cl
= (u_char
*)0;
496 * Put the chars in the from queue on the end of the to queue.
499 catq(struct clist
*from
, struct clist
*to
)
503 while ((c
= getc(from
)) != -1)