CLED 2.5 SystemV/386 part 02/03

Piercarlo Grandi pcg at cs.aber.ac.uk
Wed Aug 29 02:31:22 AEST 1990


-----------------------------cut here------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 3)."
# Contents:  cled.c.2
# Wrapped by sw at aware on Tue Aug 28 13:36:10 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cled.c.2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cled.c.2'\"
else
echo shar: Extracting \"'cled.c.2'\" \(37029 characters\)
sed "s/^X//" >'cled.c.2' <<'END_OF_FILE'
X    {
X	int                     ospl;
X
X	ospl = spl6();
X	{
X	    last = next->last;
X	    (tbp->last = last)->next = (tbp->next = next)->last = tbp;
X	}
X	splx(ospl);
X    }
X#endif
X
X    tbp->flags = TB_INSERT;
X    setup_tcap_defaults(tbp);
X    setup_key_defaults(tbp);
X
X    tty_used = tbp;
X    return tbp;
X}
X
X/*
X    Find a tty_buf that's attached to a tty struct and move it to the head of
X    the que if it's in the list.
X
X    ENTRY: Process context: task. Must not be called from interrupt. tp -
X    ptr to tty struct to match
X
X    EXIT: returns ptr to tty_buf or 0 if none found. Does not modify the
X    contents of any structures, so it is re-entrant and interruptable.
X*/
X
Xstatic struct tty_buf   *find_ttybuf(tp)
X    struct tty              *tp;
X{
X    register struct tty_buf *tbp;
X    int                     cnt = 0;
X
X    if (tty_used == 0)
X	return 0;
X
X    tbp = tty_used;
X
X    do
X    {
X	if (tbp->ttyp == tp)
X	{
X#if INKERNEL
X	    if (tbp != tty_used)
X	    {
X		int                     ospl;
X
X		ospl = spl6();
X		{
X		    register struct tty_buf *next,*last;
X
X		    tbp->next->last = tbp->last;
X		    tbp->last->next = tbp->next;
X		    next = tty_used;
X		    last = next->last;
X		    (tbp->last = last)->next = (tbp->next = next)->last = tbp;
X		    tty_used = tbp;
X		}
X		splx(ospl);
X	    }
X#endif /* INKERNEL */
X	    return tbp;
X	}
X
X	tbp = tbp->next;
X	cnt++;
X    }
X    while (tbp != tty_used && cnt < cle_ttys);
X
X    return 0;
X}
X
X/*
X    The routines cleopen, cleclose, cleread, clewrite and cleioctl are called
X    by the kernel (via a dispatch through the linesw array) and are all
X    executed at process task time. The routines cleinput and cleouput are
X    interrupt routines. Except for cleinput and cleioctl all the routines have
X    the same interface: a pointer to the tty struct assigned to the real or
X    pseudo terminal. cleinput has an extra flag argument which indicates
X    whether the input character is real or the result of the terminal sending
X    a break. cleioctl has an extra argument that has the function code the
X    ioctl is to do.
X*/
X
X/*
X    Send saved broadcast message to terminal.
X
X    ENTRY: Process context: task. tbp - ptr to tty_buf which contains the
X    message clr_flg - true if the message line is to be precleared
X
X    EXIT:  the cblock(s) holding the message are moved from the clist in
X    tty_buf to the t_outq clist.
X*/
X
Xstatic void		send_brdcst(tbp,clr_flg)
X    struct tty_buf          *tbp;
X    int                     clr_flg;
X{
X#if INKERNEL
X    int                     ospl;
X    unchar                  c;
X    struct cblock           *bp;
X    struct clist            *bl,*tpc;
X
X    tpc = &tbp->ttyp->t_outq;
X    bl = &tbp->broadcast;
X    if (clr_flg)
X    {
X	cle_putc('\r',tbp->ttyp);
X    	cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X    }
X
X    ospl = spl6();
X    {
X	while ((bp = getcb(bl)) != 0)
X	    putcb(bp,tpc);
X	kick_out(tbp->ttyp);
X    }
X    splx(ospl);
X#endif /* INKERNEL */
X}
X
X/*
X    Open line discpline
X
X    ENTRY: tbp - ptr to tty_buf to open (or 0 if not preassigned) td - ptr
X    to tty struct  to open
X*/
X
Xstatic struct tty_buf   *open_it(tbp,td)
X    register struct tty_buf *tbp;
X    struct tty              *td;
X{
X    int                     wasclosed;
X
X#if INKERNEL
X    if (tbp != 0)
X	wasclosed = !(tbp->flags&TB_OPEN);
X    else
X    {
X	garbage_collect();
X	tbp = get_ttybuf(td);
X	wasclosed = YES;
X    }
X
X    if (tbp != 0)
X    {
X	tbp->flags |= (TB_OPEN|TB_OPENING);
X	if (wasclosed)
X	{
X#if VERBOSE
X	    show_pid(1," started by process ",td);
X#endif
X	}
X    }
X    else
X    {
X	if (wasclosed)
X	{
X	    cle_puts("\rNo buffers available to start cled\r\n",td);
X	    u.u_error = ERR_NOTTYBUF;
X	}
X    }
X
X    if (wasclosed)
X	kick_out(td);
X#endif
X
X    return tbp;
X}
X
X/*
X    Open the line discipline. This procedure is called by kernel code when the
X    line discipline is selected. I haven't yet determined what exactly the
X    open is supposed to do, but since cled uses discipline 0, if IT (ld0)
X    isn't opened too, very strange terminal behavior results.
X
X    ENTRY: tp - ptr to tty struct process context: task.
X
X    EXIT:  discipline 0 is opened.
X*/
X
Xcleopen(tp)
X    struct tty              *tp;
X{
X#if INKERNEL
X    (*linesw[0].l_open) (tp);
X    (void) open_it(find_ttybuf(tp),tp);
X#endif
X
X    return 1;
X}
X
X/*
X    Close the line discpline
X
X    ENTRY: tbp - ptr to tty_buf to close (or 0 if not preassigned) td - ptr
X    to tty struct  to open
X*/
X
Xstatic void             close_it(tbp,td)
X    struct tty_buf          *tbp;
X    struct tty              *td;
X{
X#if INKERNEL
X    if (tbp != 0)
X    {
X	int                     ospl;
X
X	if (td->t_state&ISOPEN)
X	{
X#if VERBOSE
X	    show_pid(0,"\rcled stopped by process ",td);
X#endif
X	    kick_out(td);
X	}
X
X	if (tbp->readsleep)
X	{
X	    wakeup(tbp);
X	    tbp->readsleep = NO;
X	    if (td->t_state&ISOPEN)
X		tbp->flags |= TB_FLUSHIT;
X	}
X
X	ospl = spl6();
X	{
X	    tbp->flags &=~ (TB_OPEN|TB_OPENING);
X	}
X	splx(ospl);
X    }
X
X#if MULTILB
X    free_leds(tbp);
X#endif
X
X#endif
X}
X
X/*
X    Close the line discipline. This procedure is called by kernel code when
X    the line discipline is deselected. I haven't yet determined what exactly
X    the close is supposed to do, but a call to close discipline 0 is done
X    because it apparently needs it.
X
X    ENTRY: tp - ptr to tty struct process context: task.
X
X    EXIT:  discipline 0 is closed.
X*/
X
Xcleclose(tp)
X    struct tty              *tp;
X{
X    struct tty_buf	    *tbp;
X
X    tbp = find_ttybuf(tp);
X
X#if INKERNEL
X    (*tp->t_proc) (tp,T_RESUME);
X    close_it(tbp,tp);
X    delay(HZ);
X    ttyflush(tp,FWRITE|FREAD);
X    (*linesw[0].l_close) (tp);
X#endif
X
X    return 1;
X}
X
X#if INKERNEL
X
X/*
X    Input interrupt routine. This routine is called after n characters have
X    been placed in the interrupt holding buffer (t_rbuf) and/or a certain
X    time has elapsed since the last input interrupt occurred (This technique
X    tends to reduce the CPU load somewhat by bunching input character
X    processing on dumb terminal ports).
X
X    The input routine processes the characters in the device buffer, which
X    is an array, and then appends them to the raw queue, which is a clist.
X    It wakes up the waiting process, which will eventually call cleread that
X    will get the characters from the raw queue, to its internal history, and
X    then to the user.
X
X    If the line discipline is in raw mode, we check for VINTR and VQUIT and
X    send the appropriate signal. Notice that we cannot do this in cleread,
X    because cleread is only called when the user reads. We want to be able
X    to interrupt even if no read is outstanding.
X*/
X
Xcleinput(td,bflg)
X    struct tty              *td;
X    int                     bflg;
X{
X    int                     i,indx,ospl;
X    unchar		    ch,*cp,*msg;
X    struct tty_buf          *tbp;
X
X    i = 0;
X    tbp = tty_used;
X
X    if (tbp != 0)
X	do
X	{
X	    if (tbp->ttyp == td)
X		break;
X	    tbp = tbp->next;
X	    ++i;
X	}
X	while ((tbp != tty_used) && i < cle_ttys);
X
X    /*
X	If we cannot run, let ldisc 0 sort it out...
X    */
X
X    if (CLEDOFF(td->t_lflag) || tbp == 0 || tbp->ttyp != td
X	|| (tbp->ttyp == td && (tbp->flags&TB_NOLINE)))
X    {
X	(*linesw[0].l_input) (td,bflg);
X	return;
X    }
X
X    /*
X	Our input is either a break condition or rbuf.
X    */
X
X    if (bflg == L_BREAK)
X    {
X	if (!((td->t_lflag&ISIG) && (td->t_iflag&BRKINT)))
X	    return;
X
X	cp = &ch;
X	ch = td->t_cc[VINTR];
X	i = 1;
X    }
X    else
X    {
X	if (td->t_rbuf.c_ptr == 0 || td->t_rbuf.c_count >= td->t_rbuf.c_size)
X	    return;
X
X	i = td->t_rbuf.c_size - td->t_rbuf.c_count;
X	cp = (unchar *) td->t_rbuf.c_ptr;
X	td->t_rbuf.c_count = td->t_rbuf.c_size;
X    }
X
X    /*
X	Here we have cp that points at the array of chars to process,
X	and i is the number of such characters.
X    */
X
X    for (i, cp; i > 0; --i, cp++)
X    {
X	register unchar		c;
X	int                     quote;
X
X	c = *cp;
X
X	if (c == '\0')
X	    continue;
X
X	/*
X	    The switch character is very special. We cannot even
X	    escape it.
X	*/
X	if (c == td->t_cc[VSWTCH])
X	{
X	    if ((*td->t_proc) (td,T_SWTCH) != T_SWTCH)
X		return;
X	}
X
X	if (quote = (td->t_state & CLESC))
X	    td->t_state &=~ CLESC;
X
X	if (!quote)
X	{
X	    unchar			quit,intr;
X
X	    quit = td->t_cc[VQUIT];
X	    intr = td->t_cc[VINTR];
X
X	    if (c == quit || c == intr)
X	    {
X		if (!(td->t_lflag&NOFLSH))
X		    ttyflush(td,FWRITE|FREAD);
X
X		kick_out(td);
X
X		tbp->lbp->flags |= (c == intr) ? LD_INTR : LD_QUIT;
X
X		if (tbp->readsleep)
X		{
X		    tbp->flags |= TB_FLUSHIT;
X		    tbp->readsleep = NO;
X		    wakeup(tbp);
X		}
X
X		signal(td->t_pgrp,(c == intr) ? SIGINT : SIGQUIT);
X
X		return;
X	    }
X	    else if (!CLEKEY_CHAR(c)
X		&& tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_PURGE)
X	    {
X		ttyflush(td,FREAD);
X		if (tbp->readsleep)
X		{
X		    tbp->flags |= TB_FLUSHIT;
X		    break;
X		}
X	    }
X	}
X
X	if (td->t_rawq.c_cc > (TTYHOG-3) || putc(c,&td->t_rawq) == -1)
X	{
X	    tbp->flags |= TB_OVERUN;
X	    cle_putc(BEL,td);
X	    continue;
X	}
X
X	if (!quote)
X	{
X	    if (!CLEKEY_CHAR(c) && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_ESCAPE)
X		td->t_state |= CLESC;
X	    else if
X	    (
X		c == td->t_cc[VEOL]
X		|| c == td->t_cc[VEOL2]
X		|| c == td->t_cc[VEOF]
X		|| (!CLEKEY_CHAR(c)
X		    && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_NEWLINE))
X	    {
X		/* count it so rdchk() works */
X		td->t_delct++;
X	    }
X	}
X    }
X
X    if (tbp->readsleep)
X    {
X	tbp->readsleep = NO;
X	wakeup(tbp);
X    }
X
X#if M_UNIX
X    /*
X       if by some chance, we're turned on while LD 0 is reading, wake it up
X       too
X    */
X    if (td->t_state & IASLP)
X#if M_ATT
X	ttrstrt(td);
X#else
X	ttiwake(td);
X#endif
X#endif
X}
X
X/*
X    Output interrupt routine. This routine does nothing at this time. Control
X    is passed to discipline 0 for output. It normally just moves text from the
X    t_outq clist to the t_obuf output que. Null chars and timers may be set
X    appropriately depending on the char being output. This discipline has no
X    interest in changing the behaviour of the output routines.
X
X    ENTRY: td - ptr to tty struct Process context: Interrupt.
X
X    EXIT:  Characters may have been moved from t_outq to t_obuf and the
X    output started.
X*/
X
Xcleoutput(td)
X    struct tty              *td;
X{
X    return (*linesw[0].l_output) (td);
X}
X
X/*
X    read timeout routine. This is a a kludge cuz I can't figure out who's
X    zapping the tty struct out from under cled. It usually happens after the
X    cleread routine has gone to sleep. It can be forced, however by some other
X    process intentionally changing the line number or other tty flags while a
X    read is in progress. This routine helps correct the situation.
X
X    ENTRY: arg - ptr to the tty_buf belonging to the process doing the read.
X
X    EXIT: TB_TIMEOUT set in the tty flags and a wakeup is delivered.
X*/
X
Xstatic void             read_timeout(arg)
X    struct tty_buf          *arg;
X{
X    if (arg->readsleep)
X	wakeup(arg);
X    arg->readsleep = NO;
X}
X
X/*
X    Announce that's there's no room at the inn
X
X    ENTRY: tp - ptr to tty struct typ - ascii string describing buffer type
X    that we're out of
X
X    EXIT: message output to the terminal line discipline reset to ld 0.
X*/
X
Xstatic int		no_room(tp,typ)
X    struct tty              *tp;
X    unchar                  *typ;
X{
X    cle_puts("\rInsufficient ",tp);
X    cle_puts(typ,tp);
X    cle_puts(" buffers to run cled at this time.\r",tp);
X    tp->t_line = 0;
X    (*linesw[0].l_read) (tp);
X    return 1;
X}
X
X#endif /* INKERNEL */
X
X/*
X    Read a line from the terminal. This routine exits when the user types the
X    specified eol character (normally a \r).
X
X    ENTRY: Process context: task. tp - ptr to tty struct
X
X    EXIT: process sleeps until user types one of an EOL, an EOF, a QUIT or
X    an INTR character (normally an \r, ^D, DEL and ^C characters
X    respectively). The line of text input from terminal is moved to user's
X    buffer as specified by u.u_count and u.u_base. An EOF results in 0
X    chars being returned. This routine will not exit normally if an
X    interrupt or quit character is typed (the kernel takes control via the
X    signal and will cancel the I/O request without this routine going
X    through its normal exit sequence). If the terminal has been set to
X    "raw" mode, this read passes control to discipline 0, otherwise the
X    line editing functions of cled become active while the line of input is
X    being typed.
X*/
X
Xcleread(tp)
X    struct tty              *tp;
X{
X    struct led_buf          *lb;
X    struct tty_buf          *tbp;
X    unchar                  *cp;
X    int                     c,len,time_id;
X
X    tbp = find_ttybuf(tp);
X
X#if INKERNEL
X    if (tbp == 0)
X	return no_room(tp,"tty");
X
X    if (u.u_count == 0 || CLEDOFF(tp->t_lflag))
X    {
X	if (tbp != 0)
X	    tbp->flags |= TB_NOLINE;
X	(*linesw[0].l_read) (tp);
X	return 1;
X    }
X
X    if (!(tbp->flags&TB_OPEN))
X	open_it(tbp,tp);
X#endif
X
X#if !MULTILB
X    lb = tbp->lbp;
X#else
X    lb = find_ledbuf(tbp,u.u_procp);
X    if (lb == 0)
X	lb = get_ledbuf(tbp);
X#endif
X
X    if (tbp->broadcast.c_cc != 0)
X    {
X	send_brdcst(tbp,0);
X	cle_putc('\n',tp);
X	tbp->dorefresh = YES;
X    }
X
X#if INKERNEL
X    if (lb == 0)
X    {
X	close_it(tbp,tp);
X	return no_room(tp,"led");
X    }
X#endif
X
X    tbp->flags &=~ (TB_NOLINE|TB_OPENING);
X
X#if INKERNEL
X    if (lb->owed != 0)
X    {
X	len = lb->lcurs - lb->owed;
X
X	if (len > 0)
X	{
X	    if (len > u.u_count)
X		len = u.u_count;
X	    if (copyout(lb->owed,u.u_base,len) < 0)
X	    {
X		u.u_error = EFAULT;
X		return 1;
X	    }
X	    lb->owed += len;
X	    u.u_base += len;
X	    u.u_count -= len;
X	    if (lb->owed >= lb->lcurs)
X		lb->owed = 0;
X	    return 1;
X	}
X
X	lb->owed = 0;
X    }
X#endif
X
X    /*
X	Initialize command buffer and display to empty line
X    */
X    lb->current = 0;
X    lb->lastchar = sizeof lb->line - 1;
X
X    lb->lcurs = lb->line;
X    lb->rcurs = lb->lineend = lb->line + lb->lastchar;
X    *lb->lcurs = *lb->rcurs = '\0';
X
X    lb->state = NORMAL;
X
X    /*
X	Reset history pointers to bottom
X    */
X    lb->lastline = 0;
X    lb->matchlen = 0;
X
X    /*
X	Initialize flags
X    */
X    lb->flags &=~ (LD_DONE|LD_EOF|LD_INTR|LD_QUIT|LD_INSERT);
X    lb->flags |= (LD_DIRTY);
X    if (tbp->flags&TB_INSERT)
X	lb->flags |= LD_INSERT;
X    tbp->flags |= TB_READING;
X
X#if INKERNEL
X    tbp->iflag = tp->t_iflag;
X    tbp->oflag = tp->t_oflag;
X    tbp->lflag = tp->t_lflag;
X    tbp->cflag = tp->t_cflag;
X    for (c = 0; c < NCC + 2; c++)
X	tbp->cc[c] = tp->t_cc[c];
X
X    /*
X	Print any pending output
X    */
X    while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
X    {
X	kick_out(tp);
X	delay(HZ/10);
X    }
X#endif
X
X    while (!(lb->flags&LD_DONE))
X    {
X#if INKERNEL
X	int                     ospl;
X
X	ospl = spl6();
X	{
X	    /*
X		Wait for input if there is none queued
X	    */
X
X	    if (tp->t_rawq.c_cc == 0)
X	    {
X		if (tbp->dorefresh)
X		{
X		    tbp->dorefresh = NO;	
X		    splx(ospl);
X
X		    reprint(lb);
X		    kick_out(tp);
X		    continue;
X		}
X
X		if (!(tbp->flags&TB_OPEN))
X		{
X		    lb->flags |= (LD_DONE|LD_EOF);
X		    msg("Trying to cleread while CLED turned off",lb);
X		    break;
X		}
X
X		if (tp->t_line != our_lineno || CLEDOFF(tp->t_lflag))
X		{
X		    tp->t_line = our_lineno;
X		    tp->t_iflag = tbp->iflag;
X		    tp->t_oflag = tbp->oflag;
X		    tp->t_lflag = tbp->lflag;
X		    tp->t_cflag = tbp->cflag;
X		    for (c = 0; c < NCC + 2; c++)
X			tp->t_cc[c] = tbp->cc[c];
X
X		    tp->t_state |= ISOPEN;
X		    tbp->dorefresh = YES;
X
X		    msg("CLED: tty struct has been zapped. Resetting it.",lb);
X		    continue;
X		}
X
X		/*
X		    Sleep for a while for input to arrive
X		*/
X		time_id = timeout(read_timeout,tbp,HZ*15);
X		tbp->readsleep = YES;
X
X		if (sleep(tbp,(PZERO+8)|PCATCH))
X		{
X		    ospl = spl6();
X		    {
X			tbp->flags &=~ (TB_FLUSHIT|TB_READING);
X			tbp->dorefresh = tbp->readsleep = NO;
X		    }
X		    splx(ospl);
X
X		    untimeout(time_id);
X		    u.u_error = EINTR;
X
X		    return -1;
X		}
X
X		/*
X		    Alleluiah! We may have gotten something from cleinput
X		*/
X
X		untimeout(time_id);
X		splx(ospl);
X
X		while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
X		{
X		    kick_out(tp);
X		    delay(HZ/10);
X		}
X
X		if (tbp->flags&TB_FLUSHIT)
X		{
X		    bol(lb);
X		    d_eol(lb);
X
X		    ospl = spl6();
X		    {
X			tbp->flags &=~ TB_FLUSHIT;
X			tbp->dorefresh = tbp->readsleep;
X		    }
X		    splx(ospl);
X
X		    if (!(tbp->flags & TB_OPEN))
X			break;
X		}
X		continue;
X	    }
X	}
X	splx(ospl);
X#endif /* INKERNEL */
X
X	/*
X	    Get next char from the raw input queue, filled by cleinput
X	*/
X
X	c = cle_getc(tp);
X
X	if (c != 0 && lb->state == NORMAL)
X	{
X	    if (c == tp->t_cc[VERASE])
X		c = 0, lb->state = (NCC_SPC(VERASE));
X	    else if (c == tp->t_cc[VKILL])
X		c = 0, lb->state = (NCC_SPC(VKILL));
X	    else if (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
X		c = 0, lb->state = (NCC_SPC(VEOL));
X	    else if (c == tp->t_cc[VEOF])
X		c = 0, lb->state = (NCC_SPC(VEOL)), lb->flags = LD_EOF;
X	}
X
X	lb->c = c;
X	parse_it(lb);
X
X#if INKERNEL
X	kick_out(tp);
X#endif
X    }
X
X    tbp->flags &=~ TB_READING;
X
X    cp = lb->lcurs;
X    if (!(lb->flags&(LD_EOF/*|LD_INTR|LD_QUIT*/)))
X    {
X	*cp++ = '\n';
X	lb->lcurs = cp;
X    }
X
X    len = cp - lb->line;
X
X#if INKERNEL
X    if (len != 0 && !(lb->flags&(LD_INTR|LD_QUIT)))
X    {
X	if (len > u.u_count)
X	    len = u.u_count;
X	if (copyout(lb->line,u.u_base,len) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	u.u_base += len;
X	u.u_count -= len;
X	tp->t_col = 0;
X	cle_putc('\r',tp);    /* ICRNL */
X	cle_putc('\n',tp);    /* OCRNL */
X    }
X
X    /* count down the delimiter */
X    if (tp->t_delct > 0)
X	--tp->t_delct;
X
X    if (tbp->broadcast.c_cc != 0)
X    {
X	send_brdcst(tbp,0);
X	cle_putc('\r',tp);
X	cle_putc('\n',tp);
X    }
X
X    kick_out(tp);
X#else
X    strncpy(u.u_base,lb->line,len);
X    *(u.u_base + len) = 0;
X#endif /* INKERNEL */
X
X    lb->owed = (lb->line + len >= lb->lcurs) ? (unchar *) 0 : lb->line+len;
X
X    lb->promptlen = 0;
X    lb->prompt[0] = '\0';
X
X    return 1;
X}
X
X#if INKERNEL
X/*
X    Write some text to the terminal but catch any trailing data into a prompt
X    buffer. This routine is executed when no read is in progress on the
X    terminal, an lb buffer is assigned to the terminal and a write comes
X    through.
X
X    ENTRY: tbp - ptr to tty_buf assigned to terminal lb - ptr to
X    led_buf assigned to terminal u.u_base - ptr to message
X    (u.u_count has length of message)
X
X    EXIT: the text from the trailing \n (if any) of the message has been
X    copied to the prompt buffer in the led_buf. If the last char of the
X    message is a \n, then prompt buffer is left empty. If there are no
X    \n's in the message, then the whole message is appended to any
X    existing data in the prompt buffer. Chars are removed from the
X    beginning of the buffer if the length of the new message exceeds the
X    MAXPROMPT parameter.
X*/
X
Xstatic void              catch_prompt(tbp,lb)
X    struct tty_buf          *tbp;
X    struct led_buf          *lb;
X{
X#if M_SPTALLOC
X    unchar		    *prompt;
X#else
X    unchar		    prompt[MAXPROMPT+1];
X#endif
X    int			    maxlen;
X    register unchar	    *tail,*old;
X    register int	    headlen;
X
X    if (tbp->broadcast.c_cc != 0)
X	send_brdcst(tbp,1);
X
X    /*
X	If the write is zero length, we just return; if the last
X	character of the write is a newline, than the write is surely
X	not for a prompt; prompts are non NL terminated writes.
X    */
X
X    {
X	unchar           ch;
X
X	if (copyin(u.u_base + u.u_count - 1,&ch,sizeof ch) < 0)
X	    return;
X
X	if (ch == '\n')
X	{
X	    lb->promptlen = 0;
X	    lb->prompt[0] = '\0';
X	    return;
X	}
X    }
X
X#if M_SPTALLOC
X    prompt = (unchar *) Sptalloc(maxlen+1);
X#endif
X
X    /*
X	Fetch the last maxlen characters of the prompt, and null
X	terminate them.
X    */
X    maxlen = MIN(u.u_count,MAXPROMPT); /* This is at least 1 */
X    if (copyin(u.u_base + (u.u_count - maxlen),prompt,maxlen) < 0)
X	return;
X    *(tail = prompt + maxlen) = '\0';
X
X    /*
X	Determine the real prompt, which is the tail after the last
X	'\r' or '\n'. We *know* that maxlen != 0 implies tail > prompt initially.
X    */
X    do --tail; while (tail > prompt && !(*tail == '\r' || *tail == '\n'));
X    if (*tail == '\r' || *tail == '\n') tail++;
X
X    /*
X        First we assume that the head of the new prompt is empty, then we
X        check; if the old prompt was not empty and the new prompt tail did not
X        start with '\r' or '\n', and leaves some space in the prompt buffer we
X        prepend the tail of the old prompt as the head of the new one,
X        shifting it into place if necessary. We expect this to be executed
X        very rarely; actually we should probably not bother at all...
X    */
X
X    old = lb->prompt;
X
X    if (tail == prompt && lb->promptlen && !(tbp->flags&TB_WRITING)
X	&& (headlen = tail-prompt + MAXPROMPT-maxlen) > 0)
X    {
X	if (headlen >= lb->promptlen)
X	    old += lb->promptlen;
X	else
X	{
X	    bcopy(old+lb->promptlen-headlen,old,headlen);
X	    old += headlen;
X	}
X    }
X
X    /*
X	A simple while will do instead of bcopy; we assume the tail will
X	usually be very small, i.e. <= 8 chars.
X    */
X    while (*old++ = *tail++);
X    lb->promptlen = old-1 - lb->prompt;
X
X#if M_SPTALLOC
X    Sptfree(temp,maxlen+1);
X#endif
X}
X
X/*
X    Breakthru. This routine is called when a message is to be sent to the
X    terminal while a read is in progress. The message is prefixed with a
X    \r<clear_to_eol> to make room on the current line for the new message and
X    all text up to and including the last \n is transmitted to the terminal.
X    Any text from the last \n to the end of the buffer is saved in the
X    broadcast clist which is transmitted either with the next message to be
X    written or when the read completes. In any case, the refresh bit is set to
X    cause the user's command line to be reprinted after the write completes.
X
X    ENTRY: tbp - ptr to tty_buf u.u_base - ptr to message to send to
X    terminal.
X
X    EXIT: user data is transmitted to the terminal.
X*/
X
X#if BREAKTHRU
Xstatic void             breakthru(tbp)
X    struct tty_buf          *tbp;
X{
X    unchar                  last;
X    int                     len;
X    struct clist            *bcl;
X
X    if (copyin(u.u_base + u.u_count - 1,&last,1) < 0)
X	return;
X
X    bcl = &tbp->broadcast;
X
X    if (last == '\n')
X    {
X	if (bcl->c_cc > 0)
X	    send_brdcst(tbp,YES);
X	else
X	{
X	    cle_putc('\r',tbp->ttyp);
X	    cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X	}
X	tbp->dorefresh = YES;
X    }
X    else
X    {
X	int                     len,oldlen;
X	unchar                  *src,*dst;
X#if M_SPTALLOC
X	unchar                  *temp;
X#else
X	unchar                  temp[MAXPROMPT];
X#endif
X
X	len = 132;		/* assume max length */
X	if (len <= u.u_count)
X	{
X	    if (bcl->c_cc > 0)
X		send_brdcst(tbp,1);
X	}
X	else
X	{
X	    /* user data is smaller than 1 line */
X
X	    /* but would overflow */
X	    if (bcl->c_cc + u.u_count > len)
X	    {
X		send_brdcst(tbp,1);
X		cle_putc('\r',tbp->ttyp);
X		cle_putc('\n',tbp->ttyp);
X		tbp->dorefresh = YES;
X	    }
X
X	    len = u.u_count;
X	}
X
X	oldlen = len;
X
X#if M_SPTALLOC
X	temp = (unchar *) Sptalloc(oldlen + 1);
X#endif
X
X	if (copyin(u.u_base + (u.u_count - len),temp,len) < 0)
X	    return;
X
X	src = temp + len;
X	*src = '\0';
X
X	for (; len > 0; --len)
X	{
X	    unchar                  c;
X
X	    c = *--src;
X	    if (c == '\r' || c == '\n')
X	    {
X		++src;
X		break;
X	    }
X	}
X
X	/* compute real length of message */
X	len = oldlen - len;
X	if (bcl->c_cl != 0)
X	{
X	    int                     i;
X	    struct cblock           *cbkp;
X
X	    cbkp = bcl->c_cl;
X	    i = CLSIZE - cbkp->c_last;	/* room in last cblock */
X	    if (i > 0)
X	    {
X		dst = &cbkp->c_data[cbkp->c_last];
X		if (i > len)
X		    i = len;
X		len -= i;
X		u.u_count -= i;
X		bcl->c_cc += i;
X		/* move end ptr */
X		cbkp->c_last += i;
X		while (i-- > 0)
X		    *dst++ = *src++;
X	    }
X	}
X
X	if (len > 0)
X	{
X	    int                     ospl;
X	    struct clist            tcl;
X
X	    /* init our dummy clist */
X	    tcl.c_cc = 0;
X	    tcl.c_cf = tcl.c_cl = 0;
X	    u.u_count -= len;
X
X	    ospl = spl6();
X	    {
X		putcbp(&tcl,src,len);
X	    }
X	    splx(ospl);
X
X	    /* if broadcast is empty */
X	    if (bcl->c_cf == 0)
X		bcl->c_cf = tcl.c_cf;
X	    else
X		bcl->c_cl->c_next = tcl.c_cf;
X
X	    bcl->c_cc += tcl.c_cc;
X	    bcl->c_cl = tcl.c_cl;
X	}
X
X#if M_SPTALLOC
X	Sptfree(temp,oldlen + 1);
X#endif
X    }
X
X    kick_out(tbp->ttyp);
X}
X#endif /* BREAKTHRU */
X
X/*
X    Write some text to the terminal. Writes to the terminal can occur at any
X    time by any suitably privledged process. An attempt is made to determine
X    what writes constitute the output of a "prompt" string. This is done by
X    capturing and remembering in the brodcast clist a copy of the data to
X    write from the last \r or \n in the message to the end of the message.
X    Data that has no \r or \n in it is appended to any existing data in the
X    clist (often processes do single char output to the terminal so its no
X    wonder the system gets slow at times). If a led_buf has been assigned to
X    the process doing the write, then the "prompt" data is placed in the
X    led_buf instead of the broadcast clist. If a read is pending on the
X    terminal when a write is issued, only the data up to and including the
X    last \n is transmitted. The remainder is saved in the broadcast clist. If
X    data ends up being sent to the terminal, then the refresh bit is set and
X    the read process is awakened (which causes broadcast messages to
X    automatically refresh the input line).
X
X    ENTRY: Process context: task. td - ptr to tty struct
X
X    EXIT:  Write data sent to the terminal and/or stored in the broadcast
X    clist or led_buf (if one assigned).
X*/
X
Xclewrite(td)
X    struct tty              *td;
X{
X    int			    ospl;
X    struct led_buf	    *lb;
X    struct tty_buf	    *tbp;
X
X    if (CLEDOFF(td->t_lflag))
X    {
X	(*linesw[0].l_write)(td);
X	return;
X    }
X
X    tbp = find_ttybuf(td);
X    if (tbp != 0)
X    {
X#if BREAKTHRU
X	if (tbp->flags&TB_READING)
X	    breakthru(tbp);
X	else
X#else
X	if (!(tbp->flags&TB_READING))
X#endif
X	{
X#if !MULTILB
X	    lb = tbp->lbp;
X	    if (u.u_count > 0)
X		catch_prompt(tbp,lb);
X#else
X	    lb = find_ledbuf(tbp,u.u_procp);
X	    if (lb != 0)
X	    {
X		if (u.u_count > 0)
X		    catch_prompt(tbp,lb);
X	    }
X	    else
X	    {
X		if (tbp->broadcast.c_cc > 0)
X		    send_brdcst(tbp,0);
X	    }
X#endif
X	}
X	tbp->flags |= TB_WRITING;
X    }
X
X    if (u.u_count > 0)
X	    (*linesw[0].l_write)(td);
X    else    kick_out(td);
X
X    if (tbp != 0)
X    {
X	tbp->flags &=~ TB_WRITING;
X
X	ospl = spl6();
X	{
X	    if (tbp->dorefresh && tbp->readsleep)
X	    {
X		tbp->readsleep = NO;
X		wakeup(tbp);
X	    }
X	}
X	splx(ospl);
X    }
X}
X
X#if VERBOSE
Xstatic void             show_pid(disp,str,td)
X    int                     disp;
X    unchar                  *str;
X    struct tty              *td;
X{
X    unchar                  tmp[10],*s;
X
X    if (disp != 0)
X    {
X	cle_puts("\rcled version ",td);
X	cle_puts(VERSION,td);
X	cle_putc('.',td);
X	s = itoa(PATCHLEVEL,tmp,10); *s = '\0'; cle_puts(s,td);
X	cle_putc(' ',td);
X    }
X    cle_puts(str,td);
X    s = itoa(u.u_procp->p_pid,tmp,10); *s = '\0'; cle_puts(tmp,td);
X    cle_puts(" (",td);
X    s = itoa(u.u_procp->p_ppid,tmp,10); *s = '\0'; cle_puts(tmp,td);
X    cle_puts(")\r\n",td);
X    return;
X}
X#endif /* VERBOSE */
X
X/*
X    Line discipline IOCTL routine.
X
X    ENTRY: Process context: task. td - ptr to tty struct f1 - function to
X    perform
X
X    EXIT: ioctl function is performed
X*/
X
Xcleioctl(td,f1,arg,mode)
X    struct tty              *td;
X    int                     f1,mode;
X    faddr_t                 arg;
X{
X    struct tty_buf          *tbp;
X    struct led_buf          *lb;
X
X    tbp = find_ttybuf(td);
X    if (tbp != 0
X	&& ((tbp->flags&(TB_READING|TB_WRITING)) || !tbp->readsleep))
X    {
X#if VERBOSE
X	cle_puts("CLED: ioctl issued while terminal busy. stty bits may be zapped",tbp->tbp);
X#endif
X	kick_out(td);
X    }
X
X    if (f1 < LDGETCOLS)
X    {
X	if (f1 == LDCLOSE)
X	    close_it(tbp,td);
X	else if (f1 == LDOPEN || f1 == LDCHG)
X	    open_it(tbp,td);
X	(*linesw[0].l_ioctl) (td,f1,arg,mode);
X	kick_out(td);
X	return;
X    }
X
X#if CLEDIO
X    
X    garbage_collect(tbp);
X
X    if (tbp == 0)
X	tbp = get_ttybuf(td);
X
X    if (tbp == 0)
X    {
X	u.u_error = ERR_NOTTYBUF;
X	return;
X    }
X
X#if MULTILB
X    if ((lb = tbp->lbp) != 0)
X    {
X	struct led_buf          *us = 0,*parent = 0;
X
X	do
X	{
X	    if (u.u_procp->p_ppid == lb->pid)   parent = lb;
X	    if (u.u_procp->p_pid == lb->pid)    us = lb;
X	}
X	while ((lb = lb->next) != tbp->lbp);
X
X	lb = (us != 0) ? us : (parent != 0) ? parent : 0;
X    }
X#else
X    lb = tbp->lbp;
X#endif
X
X    switch (f1)
X    {
X    case LDGETCOLS:
X	if (copyout(&tbp->cols,arg,sizeof tbp->cols) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	break;
X
X    case LDSETCOLS:
X    {
X	int			    cols;
X
X	if (copyin(arg,&cols,sizeof cols) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	setcols(tbp,cols);
X    }
X	break;
X
X    case LDGETBF:
X    {
X	struct set_key          sk;
X	char                    cnt,len;
X	faddr_t                 outp;
X
X	sk.modes = 0;
X	sk.modes |= (tbp->flags&TB_INSERT) ? CLEMODE_INSERT : CLEMODE_OVER;
X	sk.kdbuf_len = CLEKEY_MAX;
X
X	if (copyout(tbp->keymap,arg + sizeof (sk),CLEKEY_MAX) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	outp = arg + sizeof (sk) + CLEKEY_MAX;
X
X	for (cnt = 0; cnt < TCAP_COUNT; ++cnt)
X	{
X	    unchar                  *s;
X
X	    if (copyout(&cnt,outp++,1) < 0)
X	    {
X		u.u_error = EFAULT;
X		return;
X	    }
X	    s = (unchar *) tbp->tcap[cnt];
X	    while (*s++);
X
X	    len = s - (unchar *) tbp->tcap[cnt];
X	    if (copyout(tbp->tcap[cnt],outp,len) < 0)
X	    {
X		u.u_error = EFAULT;
X		return;
X	    }
X	    outp += len;
X	}
X
X	sk.tcapbuf_len = outp - (arg + sizeof (sk) + CLEKEY_MAX);
X	if (copyout(&sk,arg,sizeof (sk)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X    }
X	break;
X
X    case LDSETBF:
X    {
X	struct set_key          sk;
X	int                     oldflag;
X
X	if (copyin(arg,&sk,sizeof (sk)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	oldflag = tbp->flags;
X	if (sk.modes & CLEMODE_INSERT)	tbp->flags |= TB_INSERT;
X	else if (sk.modes & CLEMODE_OVER)	tbp->flags &= ~TB_INSERT;
X
X	if (sk.kdbuf_len > CLEKEY_MAX)
X	{
X	    sk.kdbuf_len = CLEKEY_MAX;
X	    if (copyout(&sk,arg,sizeof (sk)) < 0)
X	    {
X		u.u_error = EFAULT;
X		return;
X	    }
X	    u.u_error = ERR_BADPARAM;
X	    return;
X	}
X
X	if (sk.kdbuf_len > 0)
X	{
X#if M_SPTALLOC
X	    unchar                  *tmp,*kp;
X#else
X	    unchar                  tmp[100],*kp;
X#endif
X	    int                     cnt,size;
X
X	    size = sk.kdbuf_len * 2;
X#if M_SPTALLOC
X	    kp = tmp = (unchar *) Sptalloc(size);
X#else
X	    if (size > sizeof (tmp))
X	    {
X		u.u_error = ERR_BADPARAM;
X		return;
X	    }
X	    kp = tmp;
X#endif
X
X	    if (copyin(arg + sizeof (sk),tmp,size) < 0)
X	    {
X		u.u_error = EFAULT;
X		return;
X	    }
X	    for (cnt = 0; cnt < sk.kdbuf_len; ++cnt)
X	    {
X		int                     key,func;
X
X		key = *kp++;
X		func = *kp++;
X		if (key >= CLEKEY_MAX || func >= CLEFUN_MAX)
X		{
X#if M_SPTALLOC
X		    Sptfree(tmp,size);
X#endif
X		    sk.kdbuf_len = cnt;
X		    copyout(&sk,arg,sizeof (sk));
X		    u.u_error = ERR_BADPARAM;
X		    return;
X		}
X		tbp->keymap[CLEKEY_CMD(key)] = func;
X	    }
X#if M_SPTALLOC
X	    Sptfree(tmp,size);
X#endif
X	}
X
X	if (sk.tcapbuf_len > 0)
X	{
X	    setup_tcap_defaults(tbp);
X	    if (sk.tcapbuf_len > 1)
X	    {
X		unchar                  *s;
X		int                     nfg = 0;
X#if M_SPTALLOC
X		s = tbp->tcstrings = (unchar *) Sptalloc(sk.tcapbuf_len);
X#else
X		s = tbp->tcstrings;
X		if (sk.tcapbuf_len > TCAP_SIZE)
X		{
X		    sk.tcapbuf_len = TCAP_SIZE;
X		    copyout(&sk,arg,sizeof (sk));
X		    u.u_error = ERR_BADPARAM;
X		    return;
X		}
X#endif
X		tbp->tclen = sk.tcapbuf_len;
X		if (copyin(arg + sizeof (sk) + sk.kdbuf_len*2,s,tbp->tclen) < 0)
X		{
X		    u.u_error = EFAULT;
X		    return;
X		}
X		while (s < tbp->tcstrings + tbp->tclen)
X		{
X		    unchar                  *ap;
X		    int                     str;
X
X		    str = *s++;
X		    if (str >= TCAP_COUNT)
X		    {
X			nfg = 1;
X			break;
X		    }
X		    ap = s;
X		    while (*ap && ap < tbp->tcstrings + tbp->tclen)
X			++ap;
X		    if (*ap != 0)
X		    {
X			nfg = 1;
X			break;
X		    }
X
X		    tbp->tcap[str] = (char *) s;
X		    s = ap + 1;
X		}
X		if (nfg)
X		{
X		    sk.tcapbuf_len = s - tbp->tcstrings;
X		    copyout(&sk,arg,sizeof (sk));
X		    u.u_error = ERR_BADPARAM;
X		    return;
X		}
X	    }
X	}
X    }
X	break;
X
X    case LDGETHB:
X	if (lb == 0)
X	{
X	    u.u_error = ERR_NOLBASS;
X	    return;
X	}
X
X	if (copyout(lb->history,arg,MAXHISTORY) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	break;
X
X    default:
X	u.u_error = ERR_BADIOCTL;
X    }
X#endif /* CLEDIO */
X}
X
X/*
X    Device driver entry points; used for backdoor setup of CLED.
X*/
X
Xcledinit(dev)
X    int                     dev;
X{
X    int                     cnt;
X
X    for (cnt = 0; cnt < linecnt; ++cnt)
X	if (linesw[cnt].l_open == cleopen)
X	    break;
X
X    if (cnt < linecnt)
X    {
X	our_lineno = cnt;
X	printf("CLED %s PL%d is ldisc %d.\n",VERSION,PATCHLEVEL,cnt);
X	garbage_collect((struct tty_buf *) 0);
X    }
X    else
X    {
X#if M_UNIX
X	cmn_err(CE_WARN,"CLED %s not in linesw table. Not installed",VERSION);
X#else
X	printf("CLED %s not in linesw table. Not installed.\n",VERSION);
X#endif
X    }
X    return;
X}
X
Xcledioctl(dev,cmd,arg,mode)
X    int                     dev,cmd,mode;
X    faddr_t                 arg;
X{
X    switch (cmd)
X    {
X
X#if CLEDIO
X    case LDGETS:
X    {
X	int                     cnt;
X	unchar                  *s;
X	struct led_buf          *lb;
X	struct tty_buf          *tbp;
X	struct cle_stats        sts;
X
X	sts.line	= our_lineno;
X	sts.ledbufs	= cle_leds;
X	sts.ttybufs	= cle_ttys;
X	sts.promptsize	= MAXPROMPT;
X	sts.linesize	= MAXLINE;
X	sts.histsize	= MAXHISTORY;
X	sts.multi_lb	= MULTILB;
X	sts.spt		= M_SPTALLOC;
X#if M_SPTALLOC
X	sts.tcapsize	= 256;
X#else
X	sts.tcapsize	= TCAP_SIZE;
X#endif
X
X	s = (unchar *) VERSION;
X	for (cnt = 0; cnt < 4; ++cnt)
X	{
X	    if ((sts.vers[cnt] = *s++) == 0)
X		break;
X	}
X
X	tbp = tty_free;
X	cnt = 0;
X	if (tbp != 0)
X	{
X	    do
X	    {
X		tbp = tbp->next;
X		++cnt;
X	    } while (tbp != tty_free && cnt < cle_ttys);
X	}
X	sts.ttybufs_used = cle_ttys - cnt;
X
X#if !MULTILB
X	sts.ledbufs_used = sts.ttybufs_used;
X#else
X	cnt = 0;
X	lb = ldb_free;
X	if (lb != 0)
X	{
X	    do
X	    {
X		lb = lb->next;
X		++cnt;
X	    }
X	    while (lb != ldb_free && cnt < cle_leds);
X	}
X
X	sts.ledbufs_used = cle_leds - cnt;
X#endif
X
X	if (copyout(&sts,arg,sizeof (struct cle_stats)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X    }
X	break;
X#endif /* CLEDIO */
X
X#if DEBUG
X    case LDGETB:
X    {
X	struct cle_buf          bfs;
X
X	bfs.lbsize = cle_leds * sizeof (struct led_buf);
X	bfs.tbsize = cle_ttys * sizeof (struct tty_buf);
X
X	bfs.lbbase = cle_buffers;
X#if MULTILB
X	bfs.lbfree = ldb_free;
X#else
X	bfs.lbfree = 0;
X#endif
X
X	bfs.tbbase = cle_ttybuf;
X	bfs.tbused = tty_used;
X	bfs.tbfree = tty_free;
X
X	bfs.procbase = proc;
X
X	if (copyout(&bfs,arg,sizeof (struct cle_buf)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	arg += sizeof (struct cle_buf);
X
X	if (copyout(cle_buffers,arg,bfs.lbsize) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	arg += bfs.lbsize;
X
X	if (copyout(cle_ttybuf,arg,bfs.tbsize) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X    }
X	break;
X
X    case LDGETTTY:
X    {
X	struct tty              *ttyp;
X
X	if (copyin(arg,&ttyp,sizeof (ttyp)) < 0
X	    || copyout(ttyp,arg,sizeof (struct tty)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X    }
X	break;
X
X    case LDGETC:
X    {
X	struct clist            *clp;
X	struct cblock           *cbp;
X	int                     cnt;
X
X	if (copyin(arg,&clp,sizeof (clp)) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X	if (clp->c_cc != 0)
X	{
X	    int                     ospl;
X
X	    ospl = spl6();
X	    {
X		cbp = clp->c_cf;
X		do
X		{
X		    unchar                  siz;
X
X		    siz = cbp->c_last - cbp->c_first;
X		    if (siz != 0)
X		    {
X			if (copyout(&siz,arg,1) < 0)
X			{
X			    u.u_error = EFAULT;
X			    return;
X			}
X			++arg;
X			if (copyout(&cbp->c_data[cbp->c_first],arg,siz) < 0)
X			{
X			    u.u_error = EFAULT;
X			    return;
X			}
X			arg += siz;
X		    }
X		    cbp = cbp->c_next;
X		} while (cbp != 0);
X	    }
X	    splx(ospl);
X	}
X
X	cnt = 0;
X	if (copyout(&cnt,arg,1) < 0)
X	{
X	    u.u_error = EFAULT;
X	    return;
X	}
X    }
X	break;
X#endif /* M_DEBUG */
X    default:
X	u.u_error = ERR_BADIOCTL;
X    }
X}
X
X#else /* INKERNEL */
X
Xstatic unchar           cmd_line[256];
Xstatic struct tty       dum_tty;
X
Xstruct termio           ostate;	/* saved tty state */
Xstruct termio           nstate;	/* values for editor mode */
X
Xmain()
X{
X    int                     c;
X
X    dum_tty.t_cc[VINTR]	    = 'C' & 0x1f;
X    dum_tty.t_cc[VQUIT]	    = '\\' & 0x1f;
X    dum_tty.t_cc[VERASE]    = RUB;
X    dum_tty.t_cc[VKILL]	    = 'U' & 0x1f;
X    dum_tty.t_cc[VEOF]	    = 'D' & 0x1f;
X    dum_tty.t_cc[VEOL]	    = 'M' & 0x1f;
X
X    ioctl(0,TCGETA,&ostate);
X    ioctl(0,TCGETA,&nstate);
X
X    nstate.c_iflag	= 0;
X    nstate.c_oflag	= 0;
X    nstate.c_lflag	= 0;
X    nstate.c_cc[VEOF]	= 1;
X    nstate.c_cc[VEOL]	= 0;
X
X    ioctl(0,TCSETA,&nstate);
X
X    u.u_base	= cmd_line;
X    u.u_count	= sizeof (cmd_line);
X
X    garbage_collect((struct tty_buf *) 0);
X
X    tty_used	= cle_ttybuf;
X    get_ttybuf(&dum_tty);
X
X    cle_puts("Outputting controls\r\n",&dum_tty);
X
X    while (cleread(&dum_tty) && strlen(cmd_line))
X	fprintf(stderr,"\r\nRead %d chars\r\n",strlen(cmd_line));
X
X    ioctl(0,TCSETA,&ostate);
X    return;
X}
X
X#endif /* INKERNEL */
END_OF_FILE
if test 37029 -ne `wc -c <'cled.c.2'`; then
    echo shar: \"'cled.c.2'\" unpacked with wrong size!
fi
# end of 'cled.c.2'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
--
Piercarlo "Peter" Grandi           | ARPA: pcg%uk.ac.aber.cs at nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcsun!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg at cs.aber.ac.uk



More information about the Alt.sources mailing list