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