149589Sbostic /*- 249589Sbostic * Copyright (c) 1982, 1986 The Regents of the University of California. 349589Sbostic * All rights reserved. 423391Smckusick * 549589Sbostic * %sccs.include.proprietary.c% 649589Sbostic * 7*56517Sbostic * @(#)tty_subr.c 7.11 (Berkeley) 10/11/92 823391Smckusick */ 91892Swnj 10*56517Sbostic #include <sys/param.h> 11*56517Sbostic #include <sys/systm.h> 12*56517Sbostic #include <sys/buf.h> 13*56517Sbostic #include <sys/ioctl.h> 14*56517Sbostic #include <sys/proc.h> 15*56517Sbostic #include <sys/tty.h> 16*56517Sbostic #include <sys/clist.h> 1732Sbill 181890Swnj char cwaiting; 191890Swnj 2035811Smarc #define setquote(cp) \ 2135811Smarc setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 2235811Smarc (int)(cp)&CROUND) 2335811Smarc #define isquote(cp) \ 2435811Smarc isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \ 2535811Smarc (int)(cp)&CROUND) 2635811Smarc #define cbptr(x) ((struct cblock *)(x)) 2735811Smarc 2832Sbill /* 2947545Skarels * Initialize clist by freeing all character blocks. 3047545Skarels */ 3147545Skarels cinit() 3247545Skarels { 3347545Skarels register int ccp; 3447545Skarels register struct cblock *cp; 3547545Skarels 3647545Skarels ccp = (int) cfree; 3747545Skarels ccp = (ccp + CROUND) & ~CROUND; 3847545Skarels for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) { 3947545Skarels cp->c_next = cfreelist; 4047545Skarels cfreelist = cp; 4147545Skarels cfreecount += CBSIZE; 4247545Skarels } 4347545Skarels } 4447545Skarels 4547545Skarels /* 4632Sbill * Character list get/put 4732Sbill */ 4832Sbill getc(p) 4912754Ssam register struct clist *p; 5032Sbill { 5132Sbill register struct cblock *bp; 5232Sbill register int c, s; 5332Sbill 5417542Skarels s = spltty(); 5532Sbill if (p->c_cc <= 0) { 5632Sbill c = -1; 5732Sbill p->c_cc = 0; 5832Sbill p->c_cf = p->c_cl = NULL; 5932Sbill } else { 6035811Smarc c = *p->c_cf & 0377; 6135811Smarc if (isquote(p->c_cf)) 6235811Smarc c |= TTY_QUOTE; 6335811Smarc p->c_cf++; 6432Sbill if (--p->c_cc<=0) { 6535811Smarc bp = cbptr(p->c_cf-1); 6635811Smarc bp = cbptr((int)bp & ~CROUND); 6732Sbill p->c_cf = NULL; 6832Sbill p->c_cl = NULL; 6932Sbill bp->c_next = cfreelist; 7032Sbill cfreelist = bp; 711890Swnj cfreecount += CBSIZE; 721890Swnj if (cwaiting) { 731890Swnj wakeup(&cwaiting); 741890Swnj cwaiting = 0; 751890Swnj } 7632Sbill } else if (((int)p->c_cf & CROUND) == 0){ 7735811Smarc bp = cbptr(p->c_cf); 7832Sbill bp--; 7932Sbill p->c_cf = bp->c_next->c_info; 8032Sbill bp->c_next = cfreelist; 8132Sbill cfreelist = bp; 821890Swnj cfreecount += CBSIZE; 831890Swnj if (cwaiting) { 841890Swnj wakeup(&cwaiting); 851890Swnj cwaiting = 0; 861890Swnj } 8732Sbill } 8832Sbill } 8932Sbill splx(s); 9026279Skarels return (c); 9132Sbill } 9232Sbill 9332Sbill /* 9432Sbill * copy clist to buffer. 9532Sbill * return number of bytes moved. 9632Sbill */ 9732Sbill q_to_b(q, cp, cc) 989761Ssam register struct clist *q; 999761Ssam register char *cp; 10052501Storek int cc; 10132Sbill { 10232Sbill register struct cblock *bp; 10352501Storek register int s, nc; 10432Sbill char *acp; 10532Sbill 10632Sbill if (cc <= 0) 10726279Skarels return (0); 10817542Skarels s = spltty(); 10932Sbill if (q->c_cc <= 0) { 11032Sbill q->c_cc = 0; 11132Sbill q->c_cf = q->c_cl = NULL; 1121890Swnj splx(s); 11326279Skarels return (0); 11432Sbill } 11532Sbill acp = cp; 11632Sbill 11717542Skarels while (cc) { 11826279Skarels nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND); 11955058Spendry nc = min(nc, cc); 12055058Spendry nc = min(nc, q->c_cc); 12117542Skarels (void) bcopy(q->c_cf, cp, (unsigned)nc); 12217542Skarels q->c_cf += nc; 12317542Skarels q->c_cc -= nc; 12417542Skarels cc -= nc; 12517542Skarels cp += nc; 12617542Skarels if (q->c_cc <= 0) { 12735811Smarc bp = cbptr(q->c_cf - 1); 12835811Smarc bp = cbptr((int)bp & ~CROUND); 12932Sbill q->c_cf = q->c_cl = NULL; 13032Sbill bp->c_next = cfreelist; 13132Sbill cfreelist = bp; 1321890Swnj cfreecount += CBSIZE; 1331890Swnj if (cwaiting) { 1341890Swnj wakeup(&cwaiting); 1351890Swnj cwaiting = 0; 1361890Swnj } 13732Sbill break; 13832Sbill } 13932Sbill if (((int)q->c_cf & CROUND) == 0) { 14035811Smarc bp = cbptr(q->c_cf); 14132Sbill bp--; 14232Sbill q->c_cf = bp->c_next->c_info; 14332Sbill bp->c_next = cfreelist; 14432Sbill cfreelist = bp; 1451890Swnj cfreecount += CBSIZE; 1461890Swnj if (cwaiting) { 1471890Swnj wakeup(&cwaiting); 1481890Swnj cwaiting = 0; 1491890Swnj } 15032Sbill } 15132Sbill } 15232Sbill splx(s); 15326279Skarels return (cp-acp); 15432Sbill } 15532Sbill 15632Sbill /* 15732Sbill * Return count of contiguous characters 15832Sbill * in clist starting at q->c_cf. 15932Sbill * Stop counting if flag&character is non-null. 16032Sbill */ 16132Sbill ndqb(q, flag) 1629761Ssam register struct clist *q; 16352501Storek int flag; 16432Sbill { 16552501Storek register int cc, s; 16632Sbill 16717542Skarels s = spltty(); 16832Sbill if (q->c_cc <= 0) { 16932Sbill cc = -q->c_cc; 17032Sbill goto out; 17132Sbill } 17232Sbill cc = ((int)q->c_cf + CBSIZE) & ~CROUND; 17332Sbill cc -= (int)q->c_cf; 17432Sbill if (q->c_cc < cc) 17532Sbill cc = q->c_cc; 17632Sbill if (flag) { 17732Sbill register char *p, *end; 17832Sbill 17932Sbill p = q->c_cf; 18032Sbill end = p; 18132Sbill end += cc; 18232Sbill while (p < end) { 18332Sbill if (*p & flag) { 1841890Swnj cc = (int)p; 1851890Swnj cc -= (int)q->c_cf; 18632Sbill break; 18732Sbill } 18832Sbill p++; 18932Sbill } 19032Sbill } 19132Sbill out: 19232Sbill splx(s); 19326279Skarels return (cc); 19432Sbill } 19532Sbill 19632Sbill /* 1971890Swnj * Flush cc bytes from q. 19832Sbill */ 19932Sbill ndflush(q, cc) 20012754Ssam register struct clist *q; 20152501Storek register int cc; 20232Sbill { 20312754Ssam register struct cblock *bp; 20412754Ssam char *end; 20512754Ssam int rem, s; 20632Sbill 20717542Skarels s = spltty(); 20826279Skarels if (q->c_cc <= 0) 20932Sbill goto out; 2101890Swnj while (cc>0 && q->c_cc) { 21135811Smarc bp = cbptr((int)q->c_cf & ~CROUND); 2121890Swnj if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) { 2131890Swnj end = q->c_cl; 2141890Swnj } else { 2151890Swnj end = (char *)((int)bp + sizeof (struct cblock)); 2161890Swnj } 2171890Swnj rem = end - q->c_cf; 2181890Swnj if (cc >= rem) { 2191890Swnj cc -= rem; 2201890Swnj q->c_cc -= rem; 22132Sbill q->c_cf = bp->c_next->c_info; 2221890Swnj bp->c_next = cfreelist; 2231890Swnj cfreelist = bp; 2241890Swnj cfreecount += CBSIZE; 2251890Swnj if (cwaiting) { 2261890Swnj wakeup(&cwaiting); 2271890Swnj cwaiting = 0; 2281890Swnj } 22932Sbill } else { 2301890Swnj q->c_cc -= cc; 2311890Swnj q->c_cf += cc; 2321890Swnj if (q->c_cc <= 0) { 2331890Swnj bp->c_next = cfreelist; 2341890Swnj cfreelist = bp; 2351890Swnj cfreecount += CBSIZE; 2361890Swnj if (cwaiting) { 2371890Swnj wakeup(&cwaiting); 2381890Swnj cwaiting = 0; 2391890Swnj } 2401890Swnj } 2411890Swnj break; 24232Sbill } 2431890Swnj } 2441890Swnj if (q->c_cc <= 0) { 24532Sbill q->c_cf = q->c_cl = NULL; 2461890Swnj q->c_cc = 0; 24732Sbill } 24832Sbill out: 24932Sbill splx(s); 25032Sbill } 251172Sbill 2521890Swnj 25332Sbill putc(c, p) 25452501Storek int c; 25512754Ssam register struct clist *p; 25632Sbill { 25732Sbill register struct cblock *bp; 25832Sbill register char *cp; 25952501Storek register int s; 26032Sbill 26117542Skarels s = spltty(); 26235811Smarc if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { /* no cblocks yet */ 26332Sbill if ((bp = cfreelist) == NULL) { 26432Sbill splx(s); 26526279Skarels return (-1); 26632Sbill } 26732Sbill cfreelist = bp->c_next; 2681890Swnj cfreecount -= CBSIZE; 26932Sbill bp->c_next = NULL; 27035811Smarc bzero(bp->c_quote, CBQSIZE); 27132Sbill p->c_cf = cp = bp->c_info; 27232Sbill } else if (((int)cp & CROUND) == 0) { 27335811Smarc bp = cbptr(cp) - 1; /* pointer arith */ 27432Sbill if ((bp->c_next = cfreelist) == NULL) { 27532Sbill splx(s); 27626279Skarels return (-1); 27732Sbill } 27832Sbill bp = bp->c_next; 27932Sbill cfreelist = bp->c_next; 2801890Swnj cfreecount -= CBSIZE; 28132Sbill bp->c_next = NULL; 28232Sbill cp = bp->c_info; 28332Sbill } 28435811Smarc if (c&TTY_QUOTE) 28535811Smarc setquote(cp); 28632Sbill *cp++ = c; 28732Sbill p->c_cc++; 28832Sbill p->c_cl = cp; 28932Sbill splx(s); 29026279Skarels return (0); 29132Sbill } 29232Sbill 29332Sbill /* 29432Sbill * copy buffer to clist. 29532Sbill * return number of bytes not transfered. 29632Sbill */ 29732Sbill b_to_q(cp, cc, q) 29812754Ssam register char *cp; 29912754Ssam struct clist *q; 30012754Ssam register int cc; 30132Sbill { 30232Sbill register char *cq; 30332Sbill register struct cblock *bp; 30452501Storek register int s, nc; 30517542Skarels int acc; 30632Sbill 30732Sbill if (cc <= 0) 30826279Skarels return (0); 30917542Skarels acc = cc; 31017542Skarels s = spltty(); 31117542Skarels if ((cq = q->c_cl) == NULL || q->c_cc < 0) { 31217542Skarels if ((bp = cfreelist) == NULL) 31317542Skarels goto out; 31417542Skarels cfreelist = bp->c_next; 31517542Skarels cfreecount -= CBSIZE; 31635811Smarc bzero(bp->c_quote, CBQSIZE); 31717542Skarels bp->c_next = NULL; 31817542Skarels q->c_cf = cq = bp->c_info; 31917542Skarels } 32017542Skarels 32117542Skarels while (cc) { 32232Sbill if (((int)cq & CROUND) == 0) { 32335811Smarc bp = cbptr(cq) - 1; 32417542Skarels if ((bp->c_next = cfreelist) == NULL) 32517542Skarels goto out; 32632Sbill bp = bp->c_next; 32732Sbill cfreelist = bp->c_next; 3281890Swnj cfreecount -= CBSIZE; 32935811Smarc bzero(bp->c_quote, CBQSIZE); 33032Sbill bp->c_next = NULL; 33117542Skarels cq = bp->c_info; 33232Sbill } 33355058Spendry nc = min(cc, sizeof (struct cblock) - ((int)cq & CROUND)); 33417542Skarels (void) bcopy(cp, cq, (unsigned)nc); 33517542Skarels cp += nc; 33617542Skarels cq += nc; 33717542Skarels cc -= nc; 33832Sbill } 33917542Skarels out: 34017542Skarels q->c_cl = cq; 34117542Skarels q->c_cc += acc - cc; 34217542Skarels splx(s); 34317368Ssam return (cc); 34432Sbill } 34532Sbill 34632Sbill /* 347172Sbill * Given a non-NULL pointter into the list (like c_cf which 348172Sbill * always points to a real character if non-NULL) return the pointer 349172Sbill * to the next character in the list or return NULL if no more chars. 350172Sbill * 351172Sbill * Callers must not allow getc's to happen between nextc's so that the 352172Sbill * pointer becomes invalid. Note that interrupts are NOT masked. 353172Sbill */ 354172Sbill char * 35535811Smarc nextc(p, cp, c) 35612754Ssam register struct clist *p; 35712754Ssam register char *cp; 35835811Smarc register int *c; 359172Sbill { 360172Sbill 361172Sbill if (p->c_cc && ++cp != p->c_cl) { 36235811Smarc if (((int)cp & CROUND) == 0) { 36335811Smarc cp = (cbptr(cp))[-1].c_next->c_info; 36435811Smarc } 36535811Smarc *c = *cp; 36635811Smarc if (isquote(cp)) 36735811Smarc *c |= TTY_QUOTE; 368172Sbill return (cp); 369172Sbill } 370172Sbill return (0); 371172Sbill } 372172Sbill 373172Sbill /* 374172Sbill * Remove the last character in the list and return it. 375172Sbill */ 376172Sbill unputc(p) 37712754Ssam register struct clist *p; 378172Sbill { 379172Sbill register struct cblock *bp; 380172Sbill register int c, s; 381172Sbill struct cblock *obp; 382172Sbill 38317542Skarels s = spltty(); 384172Sbill if (p->c_cc <= 0) 385172Sbill c = -1; 386172Sbill else { 387172Sbill c = *--p->c_cl; 38835811Smarc if (isquote(p->c_cl)) 38935811Smarc c |= TTY_QUOTE; 390172Sbill if (--p->c_cc <= 0) { 39135811Smarc bp = cbptr(p->c_cl); 39235811Smarc bp = cbptr((int)bp & ~CROUND); 393172Sbill p->c_cl = p->c_cf = NULL; 394172Sbill bp->c_next = cfreelist; 395172Sbill cfreelist = bp; 3961890Swnj cfreecount += CBSIZE; 39735811Smarc } else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) { 398172Sbill p->c_cl = (char *)((int)p->c_cl & ~CROUND); 39935811Smarc 40035811Smarc bp = cbptr(p->c_cf); 40135811Smarc bp = cbptr((int)bp & ~CROUND); 40235811Smarc while (bp->c_next != cbptr(p->c_cl)) 403172Sbill bp = bp->c_next; 404172Sbill obp = bp; 405172Sbill p->c_cl = (char *)(bp + 1); 406172Sbill bp = bp->c_next; 407172Sbill bp->c_next = cfreelist; 408172Sbill cfreelist = bp; 4091890Swnj cfreecount += CBSIZE; 410172Sbill obp->c_next = NULL; 411172Sbill } 412172Sbill } 413172Sbill splx(s); 414172Sbill return (c); 415172Sbill } 416172Sbill 417172Sbill /* 418172Sbill * Put the chars in the from que 419172Sbill * on the end of the to que. 420172Sbill */ 421172Sbill catq(from, to) 42212754Ssam struct clist *from, *to; 423172Sbill { 42435811Smarc #ifdef notdef 42517542Skarels char bbuf[CBSIZE*4]; 42635811Smarc #endif 42752501Storek register int s, c; 428172Sbill 42917542Skarels s = spltty(); 43017542Skarels if (to->c_cc == 0) { 43117542Skarels *to = *from; 43217542Skarels from->c_cc = 0; 43317542Skarels from->c_cf = NULL; 43417542Skarels from->c_cl = NULL; 43517542Skarels splx(s); 43617542Skarels return; 43717542Skarels } 43817542Skarels splx(s); 43935811Smarc #ifdef notdef 44017542Skarels while (from->c_cc > 0) { 44117542Skarels c = q_to_b(from, bbuf, sizeof bbuf); 44217542Skarels (void) b_to_q(bbuf, c, to); 44317542Skarels } 44435811Smarc #endif 44535811Smarc /* XXX - FIX */ 44635811Smarc while ((c = getc(from)) >= 0) 44735811Smarc putc(c, to); 448172Sbill } 449172Sbill 45017542Skarels #ifdef unneeded 451172Sbill /* 45226279Skarels * Integer (short) get/put using clists. 45332Sbill */ 45417542Skarels typedef u_short word_t; 4559761Ssam 45632Sbill getw(p) 4578955Sroot register struct clist *p; 45832Sbill { 45917542Skarels register int s, c; 46017542Skarels register struct cblock *bp; 46132Sbill 46217542Skarels if (p->c_cc <= 1) 46317542Skarels return(-1); 46417542Skarels if (p->c_cc & 01) { 46517542Skarels c = getc(p); 46633398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN 46726279Skarels return (c | (getc(p)<<8)); 46826279Skarels #else 46926279Skarels return (getc(p) | (c<<8)); 47026279Skarels #endif 47117542Skarels } 47217542Skarels s = spltty(); 47335811Smarc #if BYTE_ORDER == LITTLE_ENDIAN 47429947Skarels c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1]; 47526279Skarels #else 47626279Skarels c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0]; 47726279Skarels #endif 47826279Skarels p->c_cf += sizeof (word_t); 47926279Skarels p->c_cc -= sizeof (word_t); 48017542Skarels if (p->c_cc <= 0) { 48135811Smarc bp = cbptr(p->c_cf-1); 48235811Smarc bp = cbptr((int)bp & ~CROUND); 48317542Skarels p->c_cf = NULL; 48417542Skarels p->c_cl = NULL; 48517542Skarels bp->c_next = cfreelist; 48617542Skarels cfreelist = bp; 48717542Skarels cfreecount += CBSIZE; 48817542Skarels if (cwaiting) { 48917542Skarels wakeup(&cwaiting); 49017542Skarels cwaiting = 0; 49117542Skarels } 49217542Skarels } else if (((int)p->c_cf & CROUND) == 0) { 49335811Smarc bp = cbptr(p->c_cf); 49417542Skarels bp--; 49517542Skarels p->c_cf = bp->c_next->c_info; 49617542Skarels bp->c_next = cfreelist; 49717542Skarels cfreelist = bp; 49817542Skarels cfreecount += CBSIZE; 49917542Skarels if (cwaiting) { 50017542Skarels wakeup(&cwaiting); 50117542Skarels cwaiting = 0; 50217542Skarels } 50317542Skarels } 50417542Skarels splx(s); 50517542Skarels return (c); 50632Sbill } 50732Sbill 50832Sbill putw(c, p) 5098955Sroot register struct clist *p; 51017542Skarels word_t c; 51132Sbill { 51252501Storek register int s; 51317542Skarels register struct cblock *bp; 51417542Skarels register char *cp; 51532Sbill 51617542Skarels s = spltty(); 51732Sbill if (cfreelist==NULL) { 51832Sbill splx(s); 51932Sbill return(-1); 52032Sbill } 52117542Skarels if (p->c_cc & 01) { 52233398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN 52317542Skarels (void) putc(c, p); 52417542Skarels (void) putc(c>>8, p); 52526279Skarels #else 52626279Skarels (void) putc(c>>8, p); 52726279Skarels (void) putc(c, p); 52826279Skarels #endif 52917542Skarels } else { 53017542Skarels if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) { 53117542Skarels if ((bp = cfreelist) == NULL) { 53217542Skarels splx(s); 53317542Skarels return (-1); 53417542Skarels } 53517542Skarels cfreelist = bp->c_next; 53617542Skarels cfreecount -= CBSIZE; 53717542Skarels bp->c_next = NULL; 53817542Skarels p->c_cf = cp = bp->c_info; 53917542Skarels } else if (((int)cp & CROUND) == 0) { 54035811Smarc bp = cbptr(cp) - 1; 54117542Skarels if ((bp->c_next = cfreelist) == NULL) { 54217542Skarels splx(s); 54317542Skarels return (-1); 54417542Skarels } 54517542Skarels bp = bp->c_next; 54617542Skarels cfreelist = bp->c_next; 54717542Skarels cfreecount -= CBSIZE; 54817542Skarels bp->c_next = NULL; 54917542Skarels cp = bp->c_info; 55017542Skarels } 55126279Skarels #if defined(vax) 55217542Skarels *(word_t *)cp = c; 55326279Skarels #else 55426279Skarels ((u_char *)cp)[0] = c>>8; 55526279Skarels ((u_char *)cp)[1] = c; 55626279Skarels #endif 55726279Skarels p->c_cl = cp + sizeof (word_t); 55826279Skarels p->c_cc += sizeof (word_t); 55917542Skarels } 56032Sbill splx(s); 5619761Ssam return (0); 56232Sbill } 56317542Skarels #endif unneeded 564