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