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