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