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