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