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