xref: /dragonfly/sys/kern/tty_subr.c (revision fcf6efefc03a35111797b109fa4994034ebe39ba)
1 /*
2  * Copyright (c) 1994, David Greenman
3  * All rights reserved.
4  * Copyright (c) 2003-2011 The DragonFly Project.  All rights reserved.
5  *
6  * This code is derived from software contributed to The DragonFly Project
7   * by Matthew Dillon <dillon@backplane.com>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice unmodified, this list of conditions, and the following
14  *    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.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * clist support routines
34  *
35  * The clist now contains two linear buffers c_quote and c_info, sized
36  * to c_cbmax.  The caller must hold a lock or token specific to the clist
37  * being manipulated.
38  */
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/tty.h>
44 
45 /*
46  * Allocate or reallocate clist buffers.
47  */
48 void
clist_alloc_cblocks(struct clist * cl,int ccmax)49 clist_alloc_cblocks(struct clist *cl, int ccmax)
50 {
51           short *data;
52           int count;
53           int n;
54 
55           if (ccmax == cl->c_ccmax)
56                     return;
57           if (ccmax == 0) {
58                     clist_free_cblocks(cl);
59                     return;
60           }
61           data = kmalloc(ccmax * sizeof(*data), M_TTYS, M_INTWAIT|M_ZERO);
62           /* NOTE: cl fields may now be different due to blocking */
63 
64           count = cl->c_cc;
65           if (cl->c_cc) {
66                     if (count > ccmax)
67                               count = ccmax;
68                     n = cl->c_ccmax - cl->c_cchead;
69                     if (n > count)
70                               n = count;
71                     bcopy(cl->c_data + cl->c_cchead, data, n * sizeof(*data));
72                     if (n < count) {
73                               bcopy(cl->c_data, data + n,
74                                     (count - n) * sizeof(*data));
75                     }
76           }
77           cl->c_cc = count;
78           cl->c_ccmax = ccmax;
79           cl->c_cchead = 0;
80           cl->c_data = data;
81 }
82 
83 /*
84  * Free the clist's buffer.
85  */
86 void
clist_free_cblocks(struct clist * cl)87 clist_free_cblocks(struct clist *cl)
88 {
89           short *data;
90 
91           data = cl->c_data;
92 
93           cl->c_cc = 0;
94           cl->c_ccmax = 0;
95           cl->c_cchead = 0;
96           cl->c_unused01 = 0;
97           cl->c_data = NULL;
98           if (data)
99                     kfree(data, M_TTYS);
100 }
101 
102 /*
103  * Get a character from the head of a clist.
104  */
105 int
clist_getc(struct clist * cl)106 clist_getc(struct clist *cl)
107 {
108           short c;
109           int i;
110 
111           if (cl->c_cc == 0)
112                     return -1;
113           i = cl->c_cchead;
114           c = cl->c_data[i];
115           if (++i == cl->c_ccmax)
116                     i = 0;
117           cl->c_cchead = i;
118           --cl->c_cc;
119           return ((int)c);
120 }
121 
122 /*
123  * Copy data from the clist to the destination linear buffer.
124  * Return the number of characters actually copied.
125  */
126 int
clist_qtob(struct clist * cl,char * dest,int n)127 clist_qtob(struct clist *cl, char *dest, int n)
128 {
129           int count;
130           int i;
131           short c;
132 
133           if (n > cl->c_cc)
134                     n = cl->c_cc;
135           count = n;
136           i = cl->c_cchead;
137 
138           while (n) {
139                     c = cl->c_data[i];
140                     if (++i == cl->c_ccmax)
141                               i = 0;
142                     *dest++ = (char)c;
143                     --n;
144           }
145           cl->c_cchead = i;
146           cl->c_cc -= count;
147 
148           return count;
149 }
150 
151 /*
152  * Flush characters from the head of the clist, deleting them.
153  */
154 void
ndflush(struct clist * cl,int n)155 ndflush(struct clist *cl, int n)
156 {
157           int i;
158 
159           if (n > cl->c_cc)
160                     n = cl->c_cc;
161           i = cl->c_cchead + n;
162           if (i >= cl->c_ccmax)
163                     i -= cl->c_ccmax;
164           cl->c_cchead = i;
165           cl->c_cc -= n;
166 }
167 
168 /*
169  * Append a character to the clist, return 0 on success, -1 if
170  * there is no room.  The character can be quoted by setting TTY_QUOTE.
171  */
172 int
clist_putc(int c,struct clist * cl)173 clist_putc(int c, struct clist *cl)
174 {
175           int i;
176 
177           if (cl->c_cc == cl->c_ccmax)
178                     return -1;
179           i = cl->c_cchead + cl->c_cc;
180           if (i >= cl->c_ccmax)
181                     i -= cl->c_ccmax;
182           cl->c_data[i] = (short)c & (TTY_QUOTE | TTY_CHARMASK);
183           ++cl->c_cc;
184 
185           return 0;
186 }
187 
188 /*
189  * Copy data from linear buffer to clist chain.  Return the
190  * number of characters not copied.  The data will be flagged
191  * as not being quoted.
192  */
193 int
clist_btoq(char * src,int n,struct clist * cl)194 clist_btoq(char *src, int n, struct clist *cl)
195 {
196           int i;
197           int count;
198           int remain;
199 
200           count = cl->c_ccmax - cl->c_cc;                   /* space available */
201           if (count > n)
202                     count = n;                              /* count = bytes to copy */
203           remain = n - count;                     /* remain = bytes not copied */
204 
205           i = cl->c_cchead + cl->c_cc;            /* clist write index */
206           if (i >= cl->c_ccmax)
207                     i -= cl->c_ccmax;
208 
209           while (count) {
210                     cl->c_data[i] = (short)(uint8_t)*src;
211                     if (++i == cl->c_ccmax)
212                               i = 0;
213                     ++src;
214                     --count;
215           }
216           cl->c_cc += n - remain;                           /* bytes actually copied */
217 
218           return remain;                                    /* return bytes not copied */
219 }
220 
221 /*
222  * Get the next character in the clist relative to cp.  If cp is NULL
223  * returns the first character in the clist.  The character is stored in
224  * *dst.  No clist pointers are advanced or adjusted.
225  *
226  * The returned pointer can be used as an iterator but should not be
227  * directly dereferenced.
228  */
229 void *
clist_nextc(struct clist * cl,void * cp,int * dst)230 clist_nextc(struct clist *cl, void *cp, int *dst)
231 {
232           int i;
233 
234           if (cp == NULL) {
235                     if (cl->c_cc == 0) {
236                               *dst = -1;
237                               return NULL;
238                     }
239                     cp = &cl->c_data[cl->c_cchead];
240                     *dst = (uint16_t)*(short *)cp;          /* can be quoted */
241                     return cp;
242           }
243 
244           /*
245            * Use i to calculate the next logical index to determine if
246            * there are any characters remaining.
247            */
248           i = (short *)cp - cl->c_data;
249           if (i < cl->c_cchead)
250                     i += cl->c_ccmax - cl->c_cchead;
251           else
252                     i -= cl->c_cchead;
253           if (i + 1 == cl->c_cc) {                /* no more chars */
254                     *dst = 0;
255                     return NULL;
256           }
257 
258           /*
259            * We can just use cp to iterate the next actual buffer
260            * position.
261            */
262           cp = (short *)cp + 1;                             /* next char (use pointer) */
263           if (cp == &cl->c_data[cl->c_ccmax])
264                     cp = &cl->c_data[0];
265           *dst = (uint16_t)*(short *)cp;
266 
267           return cp;
268 }
269 
270 /*
271  * "Unput" a character from a clist, returning it.
272  */
273 int
clist_unputc(struct clist * cl)274 clist_unputc(struct clist *cl)
275 {
276           int c;
277           int i;
278 
279           if (cl->c_cc == 0)
280                     return -1;
281           --cl->c_cc;
282           i = cl->c_cchead + cl->c_cc;
283           if (i >= cl->c_ccmax)
284                     i -= cl->c_ccmax;
285           c = (int)(uint16_t)cl->c_data[i];
286 
287           return c;
288 }
289 
290 /*
291  * Move characters in source clist to destination clist,
292  * preserving quote bits.  Non-critical path.
293  */
294 void
clist_catq(struct clist * cls,struct clist * cld)295 clist_catq(struct clist *cls, struct clist *cld)
296 {
297           int c;
298 
299           while ((c = clist_getc(cls)) != -1)
300                     clist_putc(c, cld);
301 }
302