Change tty code to use clist interface, but with ring buffer implementation.

Also, fix a couple of bugs in tty.c and pccons.c, and some gross kluginess
in the hp300 stuff.
This commit is contained in:
mycroft 1993-07-12 11:33:54 +00:00
parent bfc1b68bb5
commit 41b03a4a6e
2 changed files with 571 additions and 72 deletions

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)tty_pty.c 7.21 (Berkeley) 5/30/91
* $Id: tty_pty.c,v 1.7 1993/06/27 06:06:47 andrew Exp $
* $Id: tty_pty.c,v 1.8 1993/07/12 11:33:54 mycroft Exp $
*/
/*
@ -48,7 +48,6 @@
#include "tty.h"
#include "conf.h"
#include "file.h"
#include "malloc.h"
#include "proc.h"
#include "uio.h"
#include "kernel.h"
@ -74,8 +73,8 @@ struct pt_ioctl {
} pt_ioctl[NPTY];
int npty = NPTY; /* for pstat -t */
#define PF_RCOLL 0x01
#define PF_WCOLL 0x02
#define PF_COPEN 0x01 /* master open */
#define PF_SOPEN 0x02 /* slave open */
#define PF_PKT 0x08 /* packet mode */
#define PF_STOPPED 0x10 /* user told stopped */
#define PF_REMOTE 0x20 /* remote and flow controlled input */
@ -100,9 +99,7 @@ ptsopen(dev, flag, devtype, p)
if (minor(dev) >= NPTY)
return (ENXIO);
if(!pt_tty[minor(dev)]) {
MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
bzero(tp, sizeof(struct tty));
pt_tty[minor(dev)] = tp;
tp = pt_tty[minor(dev)] = ttymalloc();
} else
tp = pt_tty[minor(dev)];
if ((tp->t_state & TS_ISOPEN) == 0) {
@ -122,13 +119,15 @@ ptsopen(dev, flag, devtype, p)
tp->t_state |= TS_WOPEN;
if (flag&FNONBLOCK)
break;
if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
ttopen, 0))
return (error);
}
error = (*linesw[tp->t_line].l_open)(dev, tp);
ptcwakeup(tp, FREAD|FWRITE);
if (error = (*linesw[tp->t_line].l_open)(dev, tp))
return (error);
pt_ioctl[minor(dev)].pt_flags |= PF_SOPEN;
ptcwakeup(tp, FREAD|FWRITE);
return (0);
}
int
@ -143,6 +142,11 @@ ptsclose(dev, flag, mode, p)
(*linesw[tp->t_line].l_close)(tp, flag);
ttyclose(tp);
ptcwakeup(tp, FREAD|FWRITE);
pt_ioctl[minor(dev)].pt_flags &= ~PF_SOPEN;
if ((pt_ioctl[minor(dev)].pt_flags & PF_COPEN) == 0) {
ttyfree(tp);
pt_tty[minor(dev)] = (struct tty *)NULL;
}
return(0);
}
@ -170,22 +174,22 @@ again:
TTIPRI | PCATCH, ttybg, 0))
return (error);
}
if (RB_LEN(&tp->t_can) == 0) {
if (tp->t_canq.c_cc == 0) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
if (error = ttysleep(tp, (caddr_t)&tp->t_can,
if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
TTIPRI | PCATCH, ttyin, 0))
return (error);
goto again;
}
while (RB_LEN(&tp->t_can) > 1 && uio->uio_resid > 0)
if (ureadc(rbgetc(&tp->t_can), uio) < 0) {
while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
if (ureadc(getc(&tp->t_canq), uio) < 0) {
error = EFAULT;
break;
}
if (RB_LEN(&tp->t_can) == 1)
(void) rbgetc(&tp->t_can);
if (RB_LEN(&tp->t_can))
if (tp->t_canq.c_cc == 1)
(void) getc(&tp->t_canq);
if (tp->t_canq.c_cc)
return (error);
} else
if (tp->t_oproc)
@ -230,7 +234,6 @@ ptsstart(tp)
pti->pt_send = TIOCPKT_START;
}
ptcwakeup(tp, FREAD);
return 0;
}
@ -243,11 +246,11 @@ ptcwakeup(tp, flag)
if (flag & FREAD) {
selwakeup(&pti->pt_selr);
wakeup((caddr_t)&tp->t_out.rb_tl);
wakeup((caddr_t)&tp->t_outq.c_cl);
}
if (flag & FWRITE) {
selwakeup(&pti->pt_selw);
wakeup((caddr_t)&tp->t_raw.rb_hd);
wakeup((caddr_t)&tp->t_rawq.c_cf);
}
}
@ -269,9 +272,7 @@ ptcopen(dev, flag, devtype, p)
if (minor(dev) >= NPTY)
return (ENXIO);
if(!pt_tty[minor(dev)]) {
MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
bzero(tp, sizeof(struct tty));
pt_tty[minor(dev)] = tp;
tp = pt_tty[minor(dev)] = ttymalloc();
} else
tp = pt_tty[minor(dev)];
if (tp->t_oproc)
@ -280,7 +281,8 @@ ptcopen(dev, flag, devtype, p)
(void)(*linesw[tp->t_line].l_modem)(tp, 1);
tp->t_lflag &= ~EXTPROC;
pti = &pt_ioctl[minor(dev)];
pti->pt_flags = 0;
pti->pt_flags &= PF_SOPEN;
pti->pt_flags |= PF_COPEN;
pti->pt_send = 0;
pti->pt_ucntl = 0;
return (0);
@ -304,17 +306,11 @@ ptcclose(dev)
if (constty==tp)
constty = 0;
#if 0
/*
* currently, we do not free the pty structures once they have
* been allocated. Two reasons: cheap to keep them around, and
* I don't want to spend my time finding the exact variables that
* will tell me if the slave/master are closed and if I can free
* them. <deraadt@fsa.ca>
*/
FREE(tp, M_TTYS);
pt_ioctl[minor(dev)].pt_flags &= ~PF_COPEN;
if ((pt_ioctl[minor(dev)].pt_flags & PF_SOPEN) == 0) {
ttyfree(tp);
pt_tty[minor(dev)] = (struct tty *)NULL;
#endif
}
return (0);
}
@ -326,7 +322,7 @@ ptcread(dev, uio, flag)
{
register struct tty *tp = pt_tty[minor(dev)];
struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
char buf[BUFSIZ];
u_char buf[BUFSIZ];
int error = 0, cc;
/*
@ -357,38 +353,29 @@ ptcread(dev, uio, flag)
pti->pt_ucntl = 0;
return (0);
}
if (RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0)
if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
break;
}
if ((tp->t_state&TS_CARR_ON) == 0)
return (0); /* EOF */
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
if (error = tsleep((caddr_t)&tp->t_out.rb_tl, TTIPRI | PCATCH,
if (error = tsleep((caddr_t)&tp->t_outq.c_cl, TTIPRI | PCATCH,
ttyin, 0))
return (error);
}
if (pti->pt_flags & (PF_PKT|PF_UCNTL))
error = ureadc(0, uio);
while (uio->uio_resid > 0 && error == 0) {
#ifdef was
cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
#else
cc = min(MIN(uio->uio_resid, BUFSIZ), RB_CONTIGGET(&tp->t_out));
if (cc) {
rbunpack(tp->t_out.rb_hd, buf, cc);
tp->t_out.rb_hd =
RB_ROLLOVER(&tp->t_out, tp->t_out.rb_hd+cc);
}
#endif
if (cc <= 0)
break;
error = uiomove(buf, cc, uio);
}
if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
if (tp->t_outq.c_cc <= tp->t_lowat) {
if (tp->t_state&TS_ASLEEP) {
tp->t_state &= ~TS_ASLEEP;
wakeup((caddr_t)&tp->t_out);
wakeup((caddr_t)&tp->t_outq);
}
selwakeup(&tp->t_wsel);
}
@ -439,7 +426,7 @@ ptcselect(dev, rw, p)
*/
s = spltty();
if ((tp->t_state&TS_ISOPEN) &&
RB_LEN(&tp->t_out) && (tp->t_state&TS_TTSTOP) == 0) {
tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
splx(s);
return (1);
}
@ -458,12 +445,12 @@ ptcselect(dev, rw, p)
case FWRITE:
if (tp->t_state&TS_ISOPEN) {
if (pti->pt_flags & PF_REMOTE) {
if (RB_LEN(&tp->t_can) == 0)
if (tp->t_canq.c_cc == 0)
return (1);
} else {
if (RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can) < TTYHOG-2)
if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
return (1);
if (RB_LEN(&tp->t_can) == 0 && (tp->t_iflag&ICANON))
if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
return (1);
}
}
@ -492,12 +479,12 @@ again:
if ((tp->t_state&TS_ISOPEN) == 0)
goto block;
if (pti->pt_flags & PF_REMOTE) {
if (RB_LEN(&tp->t_can))
if (tp->t_canq.c_cc)
goto block;
while (uio->uio_resid > 0 && RB_LEN(&tp->t_can) < TTYHOG - 1) {
while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
if (cc == 0) {
cc = min(uio->uio_resid, BUFSIZ);
cc = min(cc, TTYHOG - 1 - RB_CONTIGPUT(&tp->t_can));
cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
cp = locbuf;
error = uiomove((caddr_t)cp, cc, uio);
if (error)
@ -506,21 +493,13 @@ again:
if ((tp->t_state&TS_ISOPEN) == 0)
return (EIO);
}
#ifdef was
if (cc)
(void) b_to_q((char *)cp, cc, &tp->t_canq);
#else
if (cc) {
rbpack(cp, tp->t_can.rb_tl, cc);
tp->t_can.rb_tl =
RB_ROLLOVER(&tp->t_can, tp->t_can.rb_tl+cc);
}
#endif
(void) b_to_q(cp, cc, &tp->t_canq);
cc = 0;
}
(void) putc(0, &tp->t_can);
(void) putc(0, &tp->t_canq);
ttwakeup(tp);
wakeup((caddr_t)&tp->t_can);
wakeup((caddr_t)&tp->t_canq);
return (0);
}
while (uio->uio_resid > 0) {
@ -535,9 +514,9 @@ again:
return (EIO);
}
while (cc > 0) {
if ((RB_LEN(&tp->t_raw) + RB_LEN(&tp->t_can)) >= TTYHOG - 2 &&
(RB_LEN(&tp->t_can) > 0 || !(tp->t_iflag&ICANON))) {
wakeup((caddr_t)&tp->t_raw);
if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
(tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
wakeup((caddr_t)&tp->t_rawq);
goto block;
}
(*linesw[tp->t_line].l_rint)(*cp++, tp);
@ -561,7 +540,7 @@ block:
return (EWOULDBLOCK);
return (0);
}
if (error = tsleep((caddr_t)&tp->t_raw.rb_hd, TTOPRI | PCATCH,
if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
ttyout, 0)) {
/* adjust for data copied in but not written */
uio->uio_resid += cc;
@ -654,7 +633,7 @@ ptyioctl(dev, cmd, data, flag)
case TIOCSETA:
case TIOCSETAW:
case TIOCSETAF:
while (rbgetc(&tp->t_out) >= 0)
while (getc(&tp->t_outq) >= 0)
;
break;

520
sys/kern/tty_subr.c Normal file
View File

@ -0,0 +1,520 @@
/*
* Copyright (c) 1993 Theo de Raadt
* All rights reserved.
*
* Per Lindqvist <pgd@compuram.bbt.se> supplied an almost fully working
* set of true clist functions that this is very loosely based on.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Theo de Raadt.
* 4. The name of Theo de Raadt may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* $Id: tty_subr.c,v 1.1 1993/07/12 11:35:18 mycroft Exp $
*/
#include "param.h"
#include "systm.h"
#include "buf.h"
#include "ioctl.h"
#include "tty.h"
#include "clist.h"
#include "malloc.h"
/*
* At compile time, choose:
* There are two ways the TTY_QUOTE bit can be stored. If QBITS is
* defined we allocate an array of bits -- 1/8th as much memory but
* setbit(), clrbit(), and isset() take more cpu. If QBITS is
* undefined, we just use an array of bytes.
*
* If TTY_QUOTE functionality isn't required by a line discipline,
* it can free c_cq and set it to NULL. This speeds things up,
* and also does not use any extra memory. This is useful for (say)
* a SLIP line discipline that wants a 32K ring buffer for data
* but doesn't need quoting.
*/
#define QBITS
#ifdef QBITS
#define QMEM(n) ((((n)-1)/NBBY)+1)
#else
#define QMEM(n) (n)
#endif
/*
* Initialize clists.
*/
void
cinit()
{
}
/*
* Initialize a particular clist. Ok, they are really ring buffers,
* of the specified length, with/without quoting support.
*/
int
clalloc(clp, size, quot)
struct clist *clp;
int size;
int quot;
{
MALLOC(clp->c_cs, u_char *, size, M_TTYS, M_WAITOK);
if (!clp->c_cs)
return (-1);
bzero(clp->c_cs, size);
if(quot) {
MALLOC(clp->c_cq, u_char *, QMEM(size), M_TTYS, M_WAITOK);
if (!clp->c_cq) {
FREE(clp->c_cs, M_TTYS);
return (-1);
}
bzero(clp->c_cs, QMEM(size));
} else
clp->c_cq = (u_char *)0;
clp->c_cf = clp->c_cl = (u_char *)0;
clp->c_ce = clp->c_cs + size;
clp->c_cn = size;
clp->c_cc = 0;
return (0);
}
void
clfree(clp)
struct clist *clp;
{
if(clp->c_cs)
FREE(clp->c_cs, M_TTYS);
if(clp->c_cq)
FREE(clp->c_cq, M_TTYS);
clp->c_cs = clp->c_cq = (u_char *)0;
}
/*
* Get a character from a clist.
*/
int
getc(clp)
struct clist *clp;
{
register int c = -1;
int s;
s = spltty();
if (clp->c_cc == 0)
goto out;
c = *clp->c_cf & 0xff;
if (clp->c_cq) {
#ifdef QBITS
if (isset(clp->c_cq, clp->c_cf - clp->c_cs) )
c |= TTY_QUOTE;
#else
if (*(clp->c_cf - clp->c_cs + clp->c_cq))
c |= TTY_QUOTE;
#endif
}
if (++clp->c_cf == clp->c_ce)
clp->c_cf = clp->c_cs;
if (--clp->c_cc == 0)
clp->c_cf = clp->c_cl = (u_char *)0;
out:
splx(s);
return c;
}
/*
* Copy clist to buffer.
* Return number of bytes moved.
*/
int
q_to_b(clp, cp, count)
struct clist *clp;
u_char *cp;
int count;
{
register int cc;
u_char *p = cp;
int s;
s = spltty();
/* optimize this while loop */
while (count > 0 && clp->c_cc > 0) {
cc = clp->c_cl - clp->c_cf;
if (clp->c_cf >= clp->c_cl)
cc = clp->c_ce - clp->c_cf;
if (cc > count)
cc = count;
bcopy(clp->c_cf, p, cc);
count -= cc;
p += cc;
clp->c_cc -= cc;
clp->c_cf += cc;
if (clp->c_cf == clp->c_ce)
clp->c_cf = clp->c_cs;
}
if (clp->c_cc == 0)
clp->c_cf = clp->c_cl = (u_char *)0;
splx(s);
return p - cp;
}
/*
* Return count of contiguous characters in clist.
* Stop counting if flag&character is non-null.
*/
ndqb(clp, flag)
struct clist *clp;
int flag;
{
int count = 0;
register int i;
register int cc;
int s;
s = spltty();
if ((cc = clp->c_cc) == 0 || flag == 0)
goto out;
i = clp->c_cf - clp->c_cs;
while (cc-- > 0 && (clp->c_cs[i++] & flag) == 0) {
count++;
if (i == clp->c_cn)
break;
}
out:
splx(s);
return count;
}
/*
* Flush count bytes from clist.
*/
void
ndflush(clp, count)
struct clist *clp;
int count;
{
register int cc;
int s;
s = spltty();
if (count == clp->c_cc) {
clp->c_cc = 0;
clp->c_cf = clp->c_cl = (u_char *)0;
goto out;
}
/* optimize this while loop */
while (count > 0 && clp->c_cc > 0) {
cc = clp->c_cl - clp->c_cf;
if (clp->c_cf >= clp->c_cl)
cc = clp->c_ce - clp->c_cf;
if (cc > count)
cc = count;
count -= cc;
clp->c_cc -= cc;
clp->c_cf += cc;
if (clp->c_cf == clp->c_ce)
clp->c_cf = clp->c_cs;
}
if (clp->c_cc == 0)
clp->c_cf = clp->c_cl = (u_char *)0;
out:
splx(s);
}
/*
* Put a character into the output queue.
*/
int
putc(c, clp)
int c;
struct clist *clp;
{
register u_char *q;
register int i;
int r = -1;
int s;
s = spltty();
if (clp->c_cc == clp->c_cn)
goto out;
if (clp->c_cc == 0) {
if (!clp->c_cs) {
#if defined(DIAGNOSTIC) || 1
printf("b_to_q: required clalloc\n");
#endif
if(clalloc(clp, 1024, 1)) {
out:
splx(s);
return -1;
}
}
clp->c_cf = clp->c_cl = clp->c_cs;
}
*clp->c_cl = c & 0xff;
i = clp->c_cl - clp->c_cs;
if (clp->c_cq) {
#ifdef QBITS
if (c & TTY_QUOTE)
setbit(clp->c_cq, i);
else
clrbit(clp->c_cq, i);
#else
q = clp->c_cq + i;
*q = (c & TTY_QUOTE) ? 1 : 0;
#endif
}
clp->c_cc++;
clp->c_cl++;
if (clp->c_cl == clp->c_ce)
clp->c_cl = clp->c_cs;
splx(s);
return 0;
}
#ifdef QBITS
/*
* optimized version of
*
* for (i = 0; i < len; i++)
* clrbit(cp, off + len);
*/
void
clrbits(cp, off, len)
u_char *cp;
int off;
int len;
{
int sby, sbi, eby, ebi;
register int i;
u_char mask;
if(len==1) {
clrbit(cp, off);
return;
}
sby = off / NBBY;
sbi = off % NBBY;
eby = (off+len) / NBBY;
ebi = (off+len) % NBBY;
if (sby == eby) {
mask = ((1 << (ebi - sbi)) - 1) << sbi;
cp[sby] &= ~mask;
} else {
mask = (1<<sbi) - 1;
cp[sby++] &= mask;
mask = (1<<ebi) - 1;
cp[eby] &= ~mask;
for (i = sby; i < eby; i++)
cp[i] = 0x00;
}
}
#endif
/*
* Copy buffer to clist.
* Return number of bytes not transfered.
*/
int
b_to_q(cp, count, clp)
u_char *cp;
int count;
struct clist *clp;
{
register int i, cc;
register u_char *p = cp;
int off, s;
if (count <= 0)
return 0;
s = spltty();
if (clp->c_cc == clp->c_cn)
goto out;
if (clp->c_cc == 0) {
if (!clp->c_cs) {
#if defined(DIAGNOSTIC) || 1
printf("b_to_q: required clalloc\n");
#endif
if(clalloc(clp, 1024, 1))
goto out;
}
clp->c_cf = clp->c_cl = clp->c_cs;
}
/* optimize this while loop */
while (count > 0 && clp->c_cc < clp->c_cn) {
cc = clp->c_ce - clp->c_cl;
if (clp->c_cf > clp->c_cl)
cc = clp->c_cf - clp->c_cl;
if (cc > count)
cc = count;
bcopy(p, clp->c_cl, cc);
if (clp->c_cq) {
#ifdef QBITS
clrbits(clp->c_cq, clp->c_cl - clp->c_cs, cc);
#else
bzero(clp->c_cl - clp->c_cs + clp->c_cq, cc);
#endif
}
p += cc;
count -= cc;
clp->c_cc += cc;
clp->c_cl += cc;
if (clp->c_cl == clp->c_ce)
clp->c_cl = clp->c_cs;
}
out:
splx(s);
return count;
}
static int cc;
/*
* Given a non-NULL pointer into the clist return the pointer
* to the next character in the list or return NULL if no more chars.
*
* Callers must not allow getc's to happen between firstc's and getc's
* so that the pointer becomes invalid. Note that interrupts are NOT
* masked.
*/
u_char *
nextc(clp, cp, c)
struct clist *clp;
register u_char *cp;
int *c;
{
if (clp->c_cf == cp) {
/*
* First time initialization.
*/
cc = clp->c_cc;
}
if (cc == 0 || cp == NULL)
return NULL;
if (--cc == 0)
return NULL;
if (++cp == clp->c_ce)
cp = clp->c_cs;
*c = *cp & 0xff;
if (clp->c_cq) {
#ifdef QBITS
if (isset(clp->c_cq, cp - clp->c_cs))
*c |= TTY_QUOTE;
#else
if (*(clp->c_cf - clp->c_cs + clp->c_cq))
*c |= TTY_QUOTE;
#endif
}
return cp;
}
/*
* Given a non-NULL pointer into the clist return the pointer
* to the first character in the list or return NULL if no more chars.
*
* Callers must not allow getc's to happen between firstc's and getc's
* so that the pointer becomes invalid. Note that interrupts are NOT
* masked.
*
* *c is set to the NEXT character
*/
u_char *
firstc(clp, c)
struct clist *clp;
int *c;
{
int empty = 0;
register u_char *cp;
register int i;
cc = clp->c_cc;
if (cc == 0)
return NULL;
cp = clp->c_cf;
*c = *cp & 0xff;
if(clp->c_cq) {
#ifdef QBITS
if (isset(clp->c_cq, cp - clp->c_cs))
*c |= TTY_QUOTE;
#else
if (*(cp - clp->c_cs + clp->c_cq))
*c |= TTY_QUOTE;
#endif
}
return clp->c_cf;
}
/*
* Remove the last character in the clist and return it.
*/
int
unputc(clp)
struct clist *clp;
{
unsigned int c = -1;
int s;
s = spltty();
if (clp->c_cc == 0)
goto out;
if (clp->c_cl == clp->c_cs)
clp->c_cl = clp->c_ce - 1;
else
--clp->c_cl;
clp->c_cc--;
c = *clp->c_cl & 0xff;
if (clp->c_cq) {
#ifdef QBITS
if (isset(clp->c_cq, clp->c_cl - clp->c_cs))
c |= TTY_QUOTE;
#else
if (*(clp->c_cf - clp->c_cs + clp->c_cq))
c | TTY_QUOTE;
#endif
}
if (clp->c_cc == 0)
clp->c_cf = clp->c_cl = (u_char *)0;
out:
splx(s);
return c;
}
/*
* Put the chars in the from queue on the end of the to queue.
*/
void
catq(from, to)
struct clist *from, *to;
{
int c;
while ((c = getc(from)) != -1)
putc(c, to);
}