From 41b03a4a6e67d331ef000cd3a2d972c185163c28 Mon Sep 17 00:00:00 2001 From: mycroft Date: Mon, 12 Jul 1993 11:33:54 +0000 Subject: [PATCH] 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. --- sys/kern/tty_pty.c | 123 +++++------ sys/kern/tty_subr.c | 520 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 571 insertions(+), 72 deletions(-) create mode 100644 sys/kern/tty_subr.c diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index 92fd6a0394d1..1e50abe34941 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -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); + 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 (error); + 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. - */ - FREE(tp, M_TTYS); - pt_tty[minor(dev)] = (struct tty *)NULL; -#endif + 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; + } 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; diff --git a/sys/kern/tty_subr.c b/sys/kern/tty_subr.c new file mode 100644 index 000000000000..10e402051f1b --- /dev/null +++ b/sys/kern/tty_subr.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 1993 Theo de Raadt + * All rights reserved. + * + * Per Lindqvist 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<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); +}