149589Sbostic /*-
263178Sbostic * Copyright (c) 1982, 1986, 1993
363178Sbostic * The Regents of the University of California. All rights reserved.
4*65771Sbostic * (c) UNIX System Laboratories, Inc.
5*65771Sbostic * All or some portions of this file are derived from material licensed
6*65771Sbostic * to the University of California by American Telephone and Telegraph
7*65771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65771Sbostic * the permission of UNIX System Laboratories, Inc.
923391Smckusick *
1049589Sbostic * %sccs.include.proprietary.c%
1149589Sbostic *
12*65771Sbostic * @(#)tty_subr.c 8.3 (Berkeley) 01/21/94
1323391Smckusick */
141892Swnj
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/buf.h>
1856517Sbostic #include <sys/ioctl.h>
1956517Sbostic #include <sys/proc.h>
2056517Sbostic #include <sys/tty.h>
2156517Sbostic #include <sys/clist.h>
2232Sbill
231890Swnj char cwaiting;
2461303Ssklower struct cblock *cfree, *cfreelist;
2561303Ssklower int cfreecount, nclist;
261890Swnj
2735811Smarc #define setquote(cp) \
2835811Smarc setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
2935811Smarc (int)(cp)&CROUND)
3035811Smarc #define isquote(cp) \
3135811Smarc isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
3235811Smarc (int)(cp)&CROUND)
3335811Smarc #define cbptr(x) ((struct cblock *)(x))
3435811Smarc
3532Sbill /*
3647545Skarels * Initialize clist by freeing all character blocks.
3747545Skarels */
3864411Sbostic void
clist_init()3964411Sbostic clist_init()
4047545Skarels {
4147545Skarels register int ccp;
4247545Skarels register struct cblock *cp;
4347545Skarels
4447545Skarels ccp = (int) cfree;
4547545Skarels ccp = (ccp + CROUND) & ~CROUND;
4647545Skarels for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) {
4747545Skarels cp->c_next = cfreelist;
4847545Skarels cfreelist = cp;
4947545Skarels cfreecount += CBSIZE;
5047545Skarels }
5147545Skarels }
5247545Skarels
5347545Skarels /*
5432Sbill * Character list get/put
5532Sbill */
getc(p)5632Sbill getc(p)
5712754Ssam register struct clist *p;
5832Sbill {
5932Sbill register struct cblock *bp;
6032Sbill register int c, s;
6132Sbill
6217542Skarels s = spltty();
6332Sbill if (p->c_cc <= 0) {
6432Sbill c = -1;
6532Sbill p->c_cc = 0;
6632Sbill p->c_cf = p->c_cl = NULL;
6732Sbill } else {
6835811Smarc c = *p->c_cf & 0377;
6935811Smarc if (isquote(p->c_cf))
7035811Smarc c |= TTY_QUOTE;
7135811Smarc p->c_cf++;
7232Sbill if (--p->c_cc<=0) {
7335811Smarc bp = cbptr(p->c_cf-1);
7435811Smarc bp = cbptr((int)bp & ~CROUND);
7532Sbill p->c_cf = NULL;
7632Sbill p->c_cl = NULL;
7732Sbill bp->c_next = cfreelist;
7832Sbill cfreelist = bp;
791890Swnj cfreecount += CBSIZE;
801890Swnj if (cwaiting) {
811890Swnj wakeup(&cwaiting);
821890Swnj cwaiting = 0;
831890Swnj }
8432Sbill } else if (((int)p->c_cf & CROUND) == 0){
8535811Smarc bp = cbptr(p->c_cf);
8632Sbill bp--;
8732Sbill p->c_cf = bp->c_next->c_info;
8832Sbill bp->c_next = cfreelist;
8932Sbill cfreelist = bp;
901890Swnj cfreecount += CBSIZE;
911890Swnj if (cwaiting) {
921890Swnj wakeup(&cwaiting);
931890Swnj cwaiting = 0;
941890Swnj }
9532Sbill }
9632Sbill }
9732Sbill splx(s);
9826279Skarels return (c);
9932Sbill }
10032Sbill
10132Sbill /*
10232Sbill * copy clist to buffer.
10332Sbill * return number of bytes moved.
10432Sbill */
q_to_b(q,cp,cc)10532Sbill q_to_b(q, cp, cc)
1069761Ssam register struct clist *q;
1079761Ssam register char *cp;
10852501Storek int cc;
10932Sbill {
11032Sbill register struct cblock *bp;
11152501Storek register int s, nc;
11232Sbill char *acp;
11332Sbill
11432Sbill if (cc <= 0)
11526279Skarels return (0);
11617542Skarels s = spltty();
11732Sbill if (q->c_cc <= 0) {
11832Sbill q->c_cc = 0;
11932Sbill q->c_cf = q->c_cl = NULL;
1201890Swnj splx(s);
12126279Skarels return (0);
12232Sbill }
12332Sbill acp = cp;
12432Sbill
12517542Skarels while (cc) {
12626279Skarels nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
12755058Spendry nc = min(nc, cc);
12855058Spendry nc = min(nc, q->c_cc);
12917542Skarels (void) bcopy(q->c_cf, cp, (unsigned)nc);
13017542Skarels q->c_cf += nc;
13117542Skarels q->c_cc -= nc;
13217542Skarels cc -= nc;
13317542Skarels cp += nc;
13417542Skarels if (q->c_cc <= 0) {
13535811Smarc bp = cbptr(q->c_cf - 1);
13635811Smarc bp = cbptr((int)bp & ~CROUND);
13732Sbill q->c_cf = q->c_cl = NULL;
13832Sbill bp->c_next = cfreelist;
13932Sbill cfreelist = bp;
1401890Swnj cfreecount += CBSIZE;
1411890Swnj if (cwaiting) {
1421890Swnj wakeup(&cwaiting);
1431890Swnj cwaiting = 0;
1441890Swnj }
14532Sbill break;
14632Sbill }
14732Sbill if (((int)q->c_cf & CROUND) == 0) {
14835811Smarc bp = cbptr(q->c_cf);
14932Sbill bp--;
15032Sbill q->c_cf = bp->c_next->c_info;
15132Sbill bp->c_next = cfreelist;
15232Sbill cfreelist = bp;
1531890Swnj cfreecount += CBSIZE;
1541890Swnj if (cwaiting) {
1551890Swnj wakeup(&cwaiting);
1561890Swnj cwaiting = 0;
1571890Swnj }
15832Sbill }
15932Sbill }
16032Sbill splx(s);
16126279Skarels return (cp-acp);
16232Sbill }
16332Sbill
16432Sbill /*
16532Sbill * Return count of contiguous characters
16632Sbill * in clist starting at q->c_cf.
16732Sbill * Stop counting if flag&character is non-null.
16832Sbill */
ndqb(q,flag)16932Sbill ndqb(q, flag)
1709761Ssam register struct clist *q;
17152501Storek int flag;
17232Sbill {
17352501Storek register int cc, s;
17432Sbill
17517542Skarels s = spltty();
17632Sbill if (q->c_cc <= 0) {
17732Sbill cc = -q->c_cc;
17832Sbill goto out;
17932Sbill }
18032Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
18132Sbill cc -= (int)q->c_cf;
18232Sbill if (q->c_cc < cc)
18332Sbill cc = q->c_cc;
18432Sbill if (flag) {
18532Sbill register char *p, *end;
18632Sbill
18732Sbill p = q->c_cf;
18832Sbill end = p;
18932Sbill end += cc;
19032Sbill while (p < end) {
19132Sbill if (*p & flag) {
1921890Swnj cc = (int)p;
1931890Swnj cc -= (int)q->c_cf;
19432Sbill break;
19532Sbill }
19632Sbill p++;
19732Sbill }
19832Sbill }
19932Sbill out:
20032Sbill splx(s);
20126279Skarels return (cc);
20232Sbill }
20332Sbill
20432Sbill /*
2051890Swnj * Flush cc bytes from q.
20632Sbill */
20764411Sbostic void
ndflush(q,cc)20832Sbill ndflush(q, cc)
20912754Ssam register struct clist *q;
21052501Storek register int cc;
21132Sbill {
21212754Ssam register struct cblock *bp;
21312754Ssam char *end;
21412754Ssam int rem, s;
21532Sbill
21617542Skarels s = spltty();
21726279Skarels if (q->c_cc <= 0)
21832Sbill goto out;
2191890Swnj while (cc>0 && q->c_cc) {
22035811Smarc bp = cbptr((int)q->c_cf & ~CROUND);
2211890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
2221890Swnj end = q->c_cl;
2231890Swnj } else {
2241890Swnj end = (char *)((int)bp + sizeof (struct cblock));
2251890Swnj }
2261890Swnj rem = end - q->c_cf;
2271890Swnj if (cc >= rem) {
2281890Swnj cc -= rem;
2291890Swnj q->c_cc -= rem;
23032Sbill q->c_cf = bp->c_next->c_info;
2311890Swnj bp->c_next = cfreelist;
2321890Swnj cfreelist = bp;
2331890Swnj cfreecount += CBSIZE;
2341890Swnj if (cwaiting) {
2351890Swnj wakeup(&cwaiting);
2361890Swnj cwaiting = 0;
2371890Swnj }
23832Sbill } else {
2391890Swnj q->c_cc -= cc;
2401890Swnj q->c_cf += cc;
2411890Swnj if (q->c_cc <= 0) {
2421890Swnj bp->c_next = cfreelist;
2431890Swnj cfreelist = bp;
2441890Swnj cfreecount += CBSIZE;
2451890Swnj if (cwaiting) {
2461890Swnj wakeup(&cwaiting);
2471890Swnj cwaiting = 0;
2481890Swnj }
2491890Swnj }
2501890Swnj break;
25132Sbill }
2521890Swnj }
2531890Swnj if (q->c_cc <= 0) {
25432Sbill q->c_cf = q->c_cl = NULL;
2551890Swnj q->c_cc = 0;
25632Sbill }
25732Sbill out:
25832Sbill splx(s);
25932Sbill }
260172Sbill
2611890Swnj
putc(c,p)26232Sbill putc(c, p)
26352501Storek int c;
26412754Ssam register struct clist *p;
26532Sbill {
26632Sbill register struct cblock *bp;
26732Sbill register char *cp;
26852501Storek register int s;
26932Sbill
27017542Skarels s = spltty();
27135811Smarc if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */
27232Sbill if ((bp = cfreelist) == NULL) {
27332Sbill splx(s);
27426279Skarels return (-1);
27532Sbill }
27632Sbill cfreelist = bp->c_next;
2771890Swnj cfreecount -= CBSIZE;
27832Sbill bp->c_next = NULL;
27935811Smarc bzero(bp->c_quote, CBQSIZE);
28032Sbill p->c_cf = cp = bp->c_info;
28132Sbill } else if (((int)cp & CROUND) == 0) {
28235811Smarc bp = cbptr(cp) - 1; /* pointer arith */
28332Sbill if ((bp->c_next = cfreelist) == NULL) {
28432Sbill splx(s);
28526279Skarels return (-1);
28632Sbill }
28732Sbill bp = bp->c_next;
28832Sbill cfreelist = bp->c_next;
2891890Swnj cfreecount -= CBSIZE;
29032Sbill bp->c_next = NULL;
29132Sbill cp = bp->c_info;
29232Sbill }
29335811Smarc if (c&TTY_QUOTE)
29435811Smarc setquote(cp);
29532Sbill *cp++ = c;
29632Sbill p->c_cc++;
29732Sbill p->c_cl = cp;
29832Sbill splx(s);
29926279Skarels return (0);
30032Sbill }
30132Sbill
30232Sbill /*
30332Sbill * copy buffer to clist.
30432Sbill * return number of bytes not transfered.
30532Sbill */
b_to_q(cp,cc,q)30632Sbill b_to_q(cp, cc, q)
30712754Ssam register char *cp;
30812754Ssam struct clist *q;
30912754Ssam register int cc;
31032Sbill {
31132Sbill register char *cq;
31232Sbill register struct cblock *bp;
31352501Storek register int s, nc;
31417542Skarels int acc;
31532Sbill
31632Sbill if (cc <= 0)
31726279Skarels return (0);
31817542Skarels acc = cc;
31917542Skarels s = spltty();
32017542Skarels if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
32117542Skarels if ((bp = cfreelist) == NULL)
32217542Skarels goto out;
32317542Skarels cfreelist = bp->c_next;
32417542Skarels cfreecount -= CBSIZE;
32535811Smarc bzero(bp->c_quote, CBQSIZE);
32617542Skarels bp->c_next = NULL;
32717542Skarels q->c_cf = cq = bp->c_info;
32817542Skarels }
32917542Skarels
33017542Skarels while (cc) {
33132Sbill if (((int)cq & CROUND) == 0) {
33235811Smarc bp = cbptr(cq) - 1;
33317542Skarels if ((bp->c_next = cfreelist) == NULL)
33417542Skarels goto out;
33532Sbill bp = bp->c_next;
33632Sbill cfreelist = bp->c_next;
3371890Swnj cfreecount -= CBSIZE;
33835811Smarc bzero(bp->c_quote, CBQSIZE);
33932Sbill bp->c_next = NULL;
34017542Skarels cq = bp->c_info;
34132Sbill }
34255058Spendry nc = min(cc, sizeof (struct cblock) - ((int)cq & CROUND));
34317542Skarels (void) bcopy(cp, cq, (unsigned)nc);
34417542Skarels cp += nc;
34517542Skarels cq += nc;
34617542Skarels cc -= nc;
34732Sbill }
34817542Skarels out:
34917542Skarels q->c_cl = cq;
35017542Skarels q->c_cc += acc - cc;
35117542Skarels splx(s);
35217368Ssam return (cc);
35332Sbill }
35432Sbill
35532Sbill /*
356172Sbill * Given a non-NULL pointter into the list (like c_cf which
357172Sbill * always points to a real character if non-NULL) return the pointer
358172Sbill * to the next character in the list or return NULL if no more chars.
359172Sbill *
360172Sbill * Callers must not allow getc's to happen between nextc's so that the
361172Sbill * pointer becomes invalid. Note that interrupts are NOT masked.
362172Sbill */
363172Sbill char *
nextc(p,cp,c)36435811Smarc nextc(p, cp, c)
36512754Ssam register struct clist *p;
36612754Ssam register char *cp;
36735811Smarc register int *c;
368172Sbill {
369172Sbill
370172Sbill if (p->c_cc && ++cp != p->c_cl) {
37135811Smarc if (((int)cp & CROUND) == 0) {
37235811Smarc cp = (cbptr(cp))[-1].c_next->c_info;
37335811Smarc }
37435811Smarc *c = *cp;
37535811Smarc if (isquote(cp))
37635811Smarc *c |= TTY_QUOTE;
377172Sbill return (cp);
378172Sbill }
379172Sbill return (0);
380172Sbill }
381172Sbill
382172Sbill /*
383172Sbill * Remove the last character in the list and return it.
384172Sbill */
unputc(p)385172Sbill unputc(p)
38612754Ssam register struct clist *p;
387172Sbill {
388172Sbill register struct cblock *bp;
389172Sbill register int c, s;
390172Sbill struct cblock *obp;
391172Sbill
39217542Skarels s = spltty();
393172Sbill if (p->c_cc <= 0)
394172Sbill c = -1;
395172Sbill else {
396172Sbill c = *--p->c_cl;
39735811Smarc if (isquote(p->c_cl))
39835811Smarc c |= TTY_QUOTE;
399172Sbill if (--p->c_cc <= 0) {
40035811Smarc bp = cbptr(p->c_cl);
40135811Smarc bp = cbptr((int)bp & ~CROUND);
402172Sbill p->c_cl = p->c_cf = NULL;
403172Sbill bp->c_next = cfreelist;
404172Sbill cfreelist = bp;
4051890Swnj cfreecount += CBSIZE;
40635811Smarc } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) {
407172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND);
40835811Smarc
40935811Smarc bp = cbptr(p->c_cf);
41035811Smarc bp = cbptr((int)bp & ~CROUND);
41135811Smarc while (bp->c_next != cbptr(p->c_cl))
412172Sbill bp = bp->c_next;
413172Sbill obp = bp;
414172Sbill p->c_cl = (char *)(bp + 1);
415172Sbill bp = bp->c_next;
416172Sbill bp->c_next = cfreelist;
417172Sbill cfreelist = bp;
4181890Swnj cfreecount += CBSIZE;
419172Sbill obp->c_next = NULL;
420172Sbill }
421172Sbill }
422172Sbill splx(s);
423172Sbill return (c);
424172Sbill }
425172Sbill
426172Sbill /*
427172Sbill * Put the chars in the from que
428172Sbill * on the end of the to que.
429172Sbill */
43064411Sbostic void
catq(from,to)431172Sbill catq(from, to)
43212754Ssam struct clist *from, *to;
433172Sbill {
43435811Smarc #ifdef notdef
43517542Skarels char bbuf[CBSIZE*4];
43635811Smarc #endif
43752501Storek register int s, c;
438172Sbill
43917542Skarels s = spltty();
44017542Skarels if (to->c_cc == 0) {
44117542Skarels *to = *from;
44217542Skarels from->c_cc = 0;
44317542Skarels from->c_cf = NULL;
44417542Skarels from->c_cl = NULL;
44517542Skarels splx(s);
44617542Skarels return;
44717542Skarels }
44817542Skarels splx(s);
44935811Smarc #ifdef notdef
45017542Skarels while (from->c_cc > 0) {
45117542Skarels c = q_to_b(from, bbuf, sizeof bbuf);
45217542Skarels (void) b_to_q(bbuf, c, to);
45317542Skarels }
45435811Smarc #endif
45535811Smarc /* XXX - FIX */
45635811Smarc while ((c = getc(from)) >= 0)
45735811Smarc putc(c, to);
458172Sbill }
459172Sbill
46017542Skarels #ifdef unneeded
461172Sbill /*
46226279Skarels * Integer (short) get/put using clists.
46332Sbill */
46417542Skarels typedef u_short word_t;
4659761Ssam
getw(p)46632Sbill getw(p)
4678955Sroot register struct clist *p;
46832Sbill {
46917542Skarels register int s, c;
47017542Skarels register struct cblock *bp;
47132Sbill
47217542Skarels if (p->c_cc <= 1)
47317542Skarels return(-1);
47417542Skarels if (p->c_cc & 01) {
47517542Skarels c = getc(p);
47633398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
47726279Skarels return (c | (getc(p)<<8));
47826279Skarels #else
47926279Skarels return (getc(p) | (c<<8));
48026279Skarels #endif
48117542Skarels }
48217542Skarels s = spltty();
48335811Smarc #if BYTE_ORDER == LITTLE_ENDIAN
48429947Skarels c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1];
48526279Skarels #else
48626279Skarels c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0];
48726279Skarels #endif
48826279Skarels p->c_cf += sizeof (word_t);
48926279Skarels p->c_cc -= sizeof (word_t);
49017542Skarels if (p->c_cc <= 0) {
49135811Smarc bp = cbptr(p->c_cf-1);
49235811Smarc bp = cbptr((int)bp & ~CROUND);
49317542Skarels p->c_cf = NULL;
49417542Skarels p->c_cl = NULL;
49517542Skarels bp->c_next = cfreelist;
49617542Skarels cfreelist = bp;
49717542Skarels cfreecount += CBSIZE;
49817542Skarels if (cwaiting) {
49917542Skarels wakeup(&cwaiting);
50017542Skarels cwaiting = 0;
50117542Skarels }
50217542Skarels } else if (((int)p->c_cf & CROUND) == 0) {
50335811Smarc bp = cbptr(p->c_cf);
50417542Skarels bp--;
50517542Skarels p->c_cf = bp->c_next->c_info;
50617542Skarels bp->c_next = cfreelist;
50717542Skarels cfreelist = bp;
50817542Skarels cfreecount += CBSIZE;
50917542Skarels if (cwaiting) {
51017542Skarels wakeup(&cwaiting);
51117542Skarels cwaiting = 0;
51217542Skarels }
51317542Skarels }
51417542Skarels splx(s);
51517542Skarels return (c);
51632Sbill }
51732Sbill
putw(c,p)51832Sbill putw(c, p)
5198955Sroot register struct clist *p;
52017542Skarels word_t c;
52132Sbill {
52252501Storek register int s;
52317542Skarels register struct cblock *bp;
52417542Skarels register char *cp;
52532Sbill
52617542Skarels s = spltty();
52732Sbill if (cfreelist==NULL) {
52832Sbill splx(s);
52932Sbill return(-1);
53032Sbill }
53117542Skarels if (p->c_cc & 01) {
53233398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
53317542Skarels (void) putc(c, p);
53417542Skarels (void) putc(c>>8, p);
53526279Skarels #else
53626279Skarels (void) putc(c>>8, p);
53726279Skarels (void) putc(c, p);
53826279Skarels #endif
53917542Skarels } else {
54017542Skarels if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
54117542Skarels if ((bp = cfreelist) == NULL) {
54217542Skarels splx(s);
54317542Skarels return (-1);
54417542Skarels }
54517542Skarels cfreelist = bp->c_next;
54617542Skarels cfreecount -= CBSIZE;
54717542Skarels bp->c_next = NULL;
54817542Skarels p->c_cf = cp = bp->c_info;
54917542Skarels } else if (((int)cp & CROUND) == 0) {
55035811Smarc bp = cbptr(cp) - 1;
55117542Skarels if ((bp->c_next = cfreelist) == NULL) {
55217542Skarels splx(s);
55317542Skarels return (-1);
55417542Skarels }
55517542Skarels bp = bp->c_next;
55617542Skarels cfreelist = bp->c_next;
55717542Skarels cfreecount -= CBSIZE;
55817542Skarels bp->c_next = NULL;
55917542Skarels cp = bp->c_info;
56017542Skarels }
56126279Skarels #if defined(vax)
56217542Skarels *(word_t *)cp = c;
56326279Skarels #else
56426279Skarels ((u_char *)cp)[0] = c>>8;
56526279Skarels ((u_char *)cp)[1] = c;
56626279Skarels #endif
56726279Skarels p->c_cl = cp + sizeof (word_t);
56826279Skarels p->c_cc += sizeof (word_t);
56917542Skarels }
57032Sbill splx(s);
5719761Ssam return (0);
57232Sbill }
57360348Storek #endif /* unneeded */
574