xref: /original-bsd/sys/kern/tty_subr.c (revision a1c2194a)
1 /*-
2  * Copyright (c) 1982, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  *
7  *	@(#)tty_subr.c	7.7 (Berkeley) 05/09/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "buf.h"
13 #include "ioctl.h"
14 #include "tty.h"
15 #include "clist.h"
16 
17 char	cwaiting;
18 
19 #define setquote(cp) \
20 	setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
21 		(int)(cp)&CROUND)
22 #define isquote(cp) \
23 	isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
24 		(int)(cp)&CROUND)
25 #define cbptr(x) ((struct cblock *)(x))
26 
27 /*
28  * Initialize clist by freeing all character blocks.
29  */
30 cinit()
31 {
32 	register int ccp;
33 	register struct cblock *cp;
34 
35 	ccp = (int) cfree;
36 	ccp = (ccp + CROUND) & ~CROUND;
37 	for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) {
38 		cp->c_next = cfreelist;
39 		cfreelist = cp;
40 		cfreecount += CBSIZE;
41 	}
42 }
43 
44 /*
45  * Character list get/put
46  */
47 getc(p)
48 	register struct clist *p;
49 {
50 	register struct cblock *bp;
51 	register int c, s;
52 
53 	s = spltty();
54 	if (p->c_cc <= 0) {
55 		c = -1;
56 		p->c_cc = 0;
57 		p->c_cf = p->c_cl = NULL;
58 	} else {
59 		c = *p->c_cf & 0377;
60 		if (isquote(p->c_cf))
61 			c |= TTY_QUOTE;
62 		p->c_cf++;
63 		if (--p->c_cc<=0) {
64 			bp = cbptr(p->c_cf-1);
65 			bp = cbptr((int)bp & ~CROUND);
66 			p->c_cf = NULL;
67 			p->c_cl = NULL;
68 			bp->c_next = cfreelist;
69 			cfreelist = bp;
70 			cfreecount += CBSIZE;
71 			if (cwaiting) {
72 				wakeup(&cwaiting);
73 				cwaiting = 0;
74 			}
75 		} else if (((int)p->c_cf & CROUND) == 0){
76 			bp = cbptr(p->c_cf);
77 			bp--;
78 			p->c_cf = bp->c_next->c_info;
79 			bp->c_next = cfreelist;
80 			cfreelist = bp;
81 			cfreecount += CBSIZE;
82 			if (cwaiting) {
83 				wakeup(&cwaiting);
84 				cwaiting = 0;
85 			}
86 		}
87 	}
88 	splx(s);
89 	return (c);
90 }
91 
92 /*
93  * copy clist to buffer.
94  * return number of bytes moved.
95  */
96 q_to_b(q, cp, cc)
97 	register struct clist *q;
98 	register char *cp;
99 {
100 	register struct cblock *bp;
101 	register int s;
102 	register nc;
103 	char *acp;
104 
105 	if (cc <= 0)
106 		return (0);
107 	s = spltty();
108 	if (q->c_cc <= 0) {
109 		q->c_cc = 0;
110 		q->c_cf = q->c_cl = NULL;
111 		splx(s);
112 		return (0);
113 	}
114 	acp = cp;
115 
116 	while (cc) {
117 		nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
118 		nc = MIN(nc, cc);
119 		nc = MIN(nc, q->c_cc);
120 		(void) bcopy(q->c_cf, cp, (unsigned)nc);
121 		q->c_cf += nc;
122 		q->c_cc -= nc;
123 		cc -= nc;
124 		cp += nc;
125 		if (q->c_cc <= 0) {
126 			bp = cbptr(q->c_cf - 1);
127 			bp = cbptr((int)bp & ~CROUND);
128 			q->c_cf = q->c_cl = NULL;
129 			bp->c_next = cfreelist;
130 			cfreelist = bp;
131 			cfreecount += CBSIZE;
132 			if (cwaiting) {
133 				wakeup(&cwaiting);
134 				cwaiting = 0;
135 			}
136 			break;
137 		}
138 		if (((int)q->c_cf & CROUND) == 0) {
139 			bp = cbptr(q->c_cf);
140 			bp--;
141 			q->c_cf = bp->c_next->c_info;
142 			bp->c_next = cfreelist;
143 			cfreelist = bp;
144 			cfreecount += CBSIZE;
145 			if (cwaiting) {
146 				wakeup(&cwaiting);
147 				cwaiting = 0;
148 			}
149 		}
150 	}
151 	splx(s);
152 	return (cp-acp);
153 }
154 
155 /*
156  * Return count of contiguous characters
157  * in clist starting at q->c_cf.
158  * Stop counting if flag&character is non-null.
159  */
160 ndqb(q, flag)
161 	register struct clist *q;
162 {
163 	register cc;
164 	int s;
165 
166 	s = spltty();
167 	if (q->c_cc <= 0) {
168 		cc = -q->c_cc;
169 		goto out;
170 	}
171 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
172 	cc -= (int)q->c_cf;
173 	if (q->c_cc < cc)
174 		cc = q->c_cc;
175 	if (flag) {
176 		register char *p, *end;
177 
178 		p = q->c_cf;
179 		end = p;
180 		end += cc;
181 		while (p < end) {
182 			if (*p & flag) {
183 				cc = (int)p;
184 				cc -= (int)q->c_cf;
185 				break;
186 			}
187 			p++;
188 		}
189 	}
190 out:
191 	splx(s);
192 	return (cc);
193 }
194 
195 /*
196  * Flush cc bytes from q.
197  */
198 ndflush(q, cc)
199 	register struct clist *q;
200 	register cc;
201 {
202 	register struct cblock *bp;
203 	char *end;
204 	int rem, s;
205 
206 	s = spltty();
207 	if (q->c_cc <= 0)
208 		goto out;
209 	while (cc>0 && q->c_cc) {
210 		bp = cbptr((int)q->c_cf & ~CROUND);
211 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
212 			end = q->c_cl;
213 		} else {
214 			end = (char *)((int)bp + sizeof (struct cblock));
215 		}
216 		rem = end - q->c_cf;
217 		if (cc >= rem) {
218 			cc -= rem;
219 			q->c_cc -= rem;
220 			q->c_cf = bp->c_next->c_info;
221 			bp->c_next = cfreelist;
222 			cfreelist = bp;
223 			cfreecount += CBSIZE;
224 			if (cwaiting) {
225 				wakeup(&cwaiting);
226 				cwaiting = 0;
227 			}
228 		} else {
229 			q->c_cc -= cc;
230 			q->c_cf += cc;
231 			if (q->c_cc <= 0) {
232 				bp->c_next = cfreelist;
233 				cfreelist = bp;
234 				cfreecount += CBSIZE;
235 				if (cwaiting) {
236 					wakeup(&cwaiting);
237 					cwaiting = 0;
238 				}
239 			}
240 			break;
241 		}
242 	}
243 	if (q->c_cc <= 0) {
244 		q->c_cf = q->c_cl = NULL;
245 		q->c_cc = 0;
246 	}
247 out:
248 	splx(s);
249 }
250 
251 
252 putc(c, p)
253 	register struct clist *p;
254 {
255 	register struct cblock *bp;
256 	register char *cp;
257 	register s;
258 
259 	s = spltty();
260 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {	/* no cblocks yet */
261 		if ((bp = cfreelist) == NULL) {
262 			splx(s);
263 			return (-1);
264 		}
265 		cfreelist = bp->c_next;
266 		cfreecount -= CBSIZE;
267 		bp->c_next = NULL;
268 		bzero(bp->c_quote, CBQSIZE);
269 		p->c_cf = cp = bp->c_info;
270 	} else if (((int)cp & CROUND) == 0) {
271 		bp = cbptr(cp) - 1;	/* pointer arith */
272 		if ((bp->c_next = cfreelist) == NULL) {
273 			splx(s);
274 			return (-1);
275 		}
276 		bp = bp->c_next;
277 		cfreelist = bp->c_next;
278 		cfreecount -= CBSIZE;
279 		bp->c_next = NULL;
280 		cp = bp->c_info;
281 	}
282 	if (c&TTY_QUOTE)
283 		setquote(cp);
284 	*cp++ = c;
285 	p->c_cc++;
286 	p->c_cl = cp;
287 	splx(s);
288 	return (0);
289 }
290 
291 /*
292  * copy buffer to clist.
293  * return number of bytes not transfered.
294  */
295 b_to_q(cp, cc, q)
296 	register char *cp;
297 	struct clist *q;
298 	register int cc;
299 {
300 	register char *cq;
301 	register struct cblock *bp;
302 	register s, nc;
303 	int acc;
304 
305 	if (cc <= 0)
306 		return (0);
307 	acc = cc;
308 	s = spltty();
309 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
310 		if ((bp = cfreelist) == NULL)
311 			goto out;
312 		cfreelist = bp->c_next;
313 		cfreecount -= CBSIZE;
314 		bzero(bp->c_quote, CBQSIZE);
315 		bp->c_next = NULL;
316 		q->c_cf = cq = bp->c_info;
317 	}
318 
319 	while (cc) {
320 		if (((int)cq & CROUND) == 0) {
321 			bp = cbptr(cq) - 1;
322 			if ((bp->c_next = cfreelist) == NULL)
323 				goto out;
324 			bp = bp->c_next;
325 			cfreelist = bp->c_next;
326 			cfreecount -= CBSIZE;
327 			bzero(bp->c_quote, CBQSIZE);
328 			bp->c_next = NULL;
329 			cq = bp->c_info;
330 		}
331 		nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND));
332 		(void) bcopy(cp, cq, (unsigned)nc);
333 		cp += nc;
334 		cq += nc;
335 		cc -= nc;
336 	}
337 out:
338 	q->c_cl = cq;
339 	q->c_cc += acc - cc;
340 	splx(s);
341 	return (cc);
342 }
343 
344 /*
345  * Given a non-NULL pointter into the list (like c_cf which
346  * always points to a real character if non-NULL) return the pointer
347  * to the next character in the list or return NULL if no more chars.
348  *
349  * Callers must not allow getc's to happen between nextc's so that the
350  * pointer becomes invalid.  Note that interrupts are NOT masked.
351  */
352 char *
353 nextc(p, cp, c)
354 	register struct clist *p;
355 	register char *cp;
356 	register int *c;
357 {
358 
359 	if (p->c_cc && ++cp != p->c_cl) {
360 		if (((int)cp & CROUND) == 0) {
361 			cp = (cbptr(cp))[-1].c_next->c_info;
362 		}
363 		*c = *cp;
364 		if (isquote(cp))
365 			*c |= TTY_QUOTE;
366 		return (cp);
367 	}
368 	return (0);
369 }
370 
371 /*
372  * Remove the last character in the list and return it.
373  */
374 unputc(p)
375 	register struct clist *p;
376 {
377 	register struct cblock *bp;
378 	register int c, s;
379 	struct cblock *obp;
380 
381 	s = spltty();
382 	if (p->c_cc <= 0)
383 		c = -1;
384 	else {
385 		c = *--p->c_cl;
386 		if (isquote(p->c_cl))
387 			c |= TTY_QUOTE;
388 		if (--p->c_cc <= 0) {
389 			bp = cbptr(p->c_cl);
390 			bp = cbptr((int)bp & ~CROUND);
391 			p->c_cl = p->c_cf = NULL;
392 			bp->c_next = cfreelist;
393 			cfreelist = bp;
394 			cfreecount += CBSIZE;
395 		} else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) {
396 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
397 
398 			bp = cbptr(p->c_cf);
399 			bp = cbptr((int)bp & ~CROUND);
400 			while (bp->c_next != cbptr(p->c_cl))
401 				bp = bp->c_next;
402 			obp = bp;
403 			p->c_cl = (char *)(bp + 1);
404 			bp = bp->c_next;
405 			bp->c_next = cfreelist;
406 			cfreelist = bp;
407 			cfreecount += CBSIZE;
408 			obp->c_next = NULL;
409 		}
410 	}
411 	splx(s);
412 	return (c);
413 }
414 
415 /*
416  * Put the chars in the from que
417  * on the end of the to que.
418  */
419 catq(from, to)
420 	struct clist *from, *to;
421 {
422 #ifdef notdef
423 	char bbuf[CBSIZE*4];
424 #endif
425 	register s, c;
426 
427 	s = spltty();
428 	if (to->c_cc == 0) {
429 		*to = *from;
430 		from->c_cc = 0;
431 		from->c_cf = NULL;
432 		from->c_cl = NULL;
433 		splx(s);
434 		return;
435 	}
436 	splx(s);
437 #ifdef notdef
438 	while (from->c_cc > 0) {
439 		c = q_to_b(from, bbuf, sizeof bbuf);
440 		(void) b_to_q(bbuf, c, to);
441 	}
442 #endif
443 	/* XXX - FIX */
444 	while ((c = getc(from)) >= 0)
445 		putc(c, to);
446 }
447 
448 #ifdef unneeded
449 /*
450  * Integer (short) get/put using clists.
451  */
452 typedef	u_short word_t;
453 
454 getw(p)
455 	register struct clist *p;
456 {
457 	register int s, c;
458 	register struct cblock *bp;
459 
460 	if (p->c_cc <= 1)
461 		return(-1);
462 	if (p->c_cc & 01) {
463 		c = getc(p);
464 #if BYTE_ORDER == LITTLE_ENDIAN
465 		return (c | (getc(p)<<8));
466 #else
467 		return (getc(p) | (c<<8));
468 #endif
469 	}
470 	s = spltty();
471 #if BYTE_ORDER == LITTLE_ENDIAN
472 	c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1];
473 #else
474 	c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0];
475 #endif
476 	p->c_cf += sizeof (word_t);
477 	p->c_cc -= sizeof (word_t);
478 	if (p->c_cc <= 0) {
479 		bp = cbptr(p->c_cf-1);
480 		bp = cbptr((int)bp & ~CROUND);
481 		p->c_cf = NULL;
482 		p->c_cl = NULL;
483 		bp->c_next = cfreelist;
484 		cfreelist = bp;
485 		cfreecount += CBSIZE;
486 		if (cwaiting) {
487 			wakeup(&cwaiting);
488 			cwaiting = 0;
489 		}
490 	} else if (((int)p->c_cf & CROUND) == 0) {
491 		bp = cbptr(p->c_cf);
492 		bp--;
493 		p->c_cf = bp->c_next->c_info;
494 		bp->c_next = cfreelist;
495 		cfreelist = bp;
496 		cfreecount += CBSIZE;
497 		if (cwaiting) {
498 			wakeup(&cwaiting);
499 			cwaiting = 0;
500 		}
501 	}
502 	splx(s);
503 	return (c);
504 }
505 
506 putw(c, p)
507 	register struct clist *p;
508 	word_t c;
509 {
510 	register s;
511 	register struct cblock *bp;
512 	register char *cp;
513 
514 	s = spltty();
515 	if (cfreelist==NULL) {
516 		splx(s);
517 		return(-1);
518 	}
519 	if (p->c_cc & 01) {
520 #if BYTE_ORDER == LITTLE_ENDIAN
521 		(void) putc(c, p);
522 		(void) putc(c>>8, p);
523 #else
524 		(void) putc(c>>8, p);
525 		(void) putc(c, p);
526 #endif
527 	} else {
528 		if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
529 			if ((bp = cfreelist) == NULL) {
530 				splx(s);
531 				return (-1);
532 			}
533 			cfreelist = bp->c_next;
534 			cfreecount -= CBSIZE;
535 			bp->c_next = NULL;
536 			p->c_cf = cp = bp->c_info;
537 		} else if (((int)cp & CROUND) == 0) {
538 			bp = cbptr(cp) - 1;
539 			if ((bp->c_next = cfreelist) == NULL) {
540 				splx(s);
541 				return (-1);
542 			}
543 			bp = bp->c_next;
544 			cfreelist = bp->c_next;
545 			cfreecount -= CBSIZE;
546 			bp->c_next = NULL;
547 			cp = bp->c_info;
548 		}
549 #if defined(vax)
550 		*(word_t *)cp = c;
551 #else
552 		((u_char *)cp)[0] = c>>8;
553 		((u_char *)cp)[1] = c;
554 #endif
555 		p->c_cl = cp + sizeof (word_t);
556 		p->c_cc += sizeof (word_t);
557 	}
558 	splx(s);
559 	return (0);
560 }
561 #endif unneeded
562