[comp.unix.i386] Line discipline part 4 of 4

shepperd@dms.UUCP (Dave Shepperd) (11/10/89)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by shepperd on Wed Nov  8 20:49:57 PST 1989
# Contents:  cledab
 
echo x - cledab
sed 's/^@//' > "cledab" <<'@//E*O*F cledab//'
}

static int dump_ledbuf(lb,msg)
struct led_buf *lb;
unsigned char *msg;
{
   struct led_buf *nlb;
   if (lb == 0) {
      printf("%s: lb = 0\n",msg);
      return;
   }
   nlb = lb;
   do {
      printf("%s: lb = %X, next = %X, last = %X, td = %X\n\tttybf = %X, flags = %X\n",
   		msg,nlb,nlb->next,nlb->last,nlb->ttybf->ttyp,nlb->ttybf,nlb->flags);
      nlb = nlb->next;
   } while (nlb != lb);
   return;
}

static int dump_buftree(tbp)
struct tty_buf *tbp;
{
   struct led_buf *lb;
   struct tty_buf *utbp;
   printf("Into dump_buftree(): tbp = %X\n",tbp);
   dump_ttybuf(tty_used,"Used");
   dump_ttybuf(tty_free,"Free");
   if (tbp != 0) {
      printf("lbtop = %X\n",tbp->lbtop);
      dump_ledbuf(tbp->lbtop,"Used");
   }
   dump_ledbuf(ldb_free,"Free");
   printf("Strike any key to continue: ");
   getchar();
   printf("Out of dump_buftree()\n");
}

static int dump_clist(clp,msg)
struct clist *clp;
unsigned char *msg;
{
   struct cblock *cbp;
   int size;
   printf("Dump_clist() [%s]: ptr = %X\n",msg,clp);
   if (clp == 0 || clp->c_cf == 0) {
      printf("clist is empty\n");
      return;
   }
   printf("\tcc = %d, first = %X, last = %X\n",clp->c_cc,clp->c_cf,clp->c_cl);
   cbp = clp->c_cf;
   size = 0;
   do {
      unsigned char tstr[CLSIZE+1],*dst,*src;
      int i;
      dst = tstr;
      src = &cbp->c_data[(i=cbp->c_first)];
      for (;i < cbp->c_last;++i) {
	  unsigned char c;
	  c = *src++;
	  if (c < ' ' || c > 126) c = '.';
	  *dst++ = c;
      }
      *dst = 0;
      printf("\t%X, next = %X, first = %d, last = %d, size = %d\n",
   		cbp,cbp->c_next,cbp->c_first,cbp->c_last,cbp->c_last-cbp->c_first);
      printf("\tstr = {%s}\n",tstr);
      size += cbp->c_last-cbp->c_first;
      if (cbp == clp->c_cl) break;
      cbp = cbp->c_next;
   } while (cbp != 0);
   if (size != clp->c_cc) {
      printf("\tAccumulated size of %d doesn't match c_cc size of %d\n",
      		size,clp->c_cc);
   }
   printf("Type any char to continue");
   getchar();
   printf("\n");
}
#endif

#if MULTI_LB
static struct led_buf *find_ledbuf();	/* forward reference to function */

/**************************************************************************
 * Put a led_buf back on the free list.
 */
	static int free_lb(lb,tbp)
	struct led_buf *lb;
	struct tty_buf *tbp;
/*
 * At entry:
 *	lb - ptr to led_buf to free
 *	tbp - ptr to tty_buf to which the led_buf was assigned
 *	Process context: MUST be task time.
 * At exit:
 *	buffer is placed on free list. ldb_free will be changed and
 *	tbp->lbtop may be changed if the buffer to be freed is a the top
 *	of the active que. tbp->lbtop will be set to zero if the freed
 *	lb is the only one in the list.
 */
{
    if (lb->next == lb) {	/* if end of chain */
	tbp->lbtop = 0;		/* no more lb's for this tb */
    } else {
	lb->next->last = lb->last; /* pluck ourself from the que */
	lb->last->next = lb->next;
	if (lb == tbp->lbtop) {	/* if we're at the top, move top */
	    tbp->lbtop = lb->next;
	}
    }
    if (ldb_free == 0) {	/* if the free list is empty */
	lb->next = lb->last = lb; /* then we become the only member */
    } else {			/* otherwise stick us in the que */
        lb->last = ldb_free->last;	/* our new last is his old last */
   	lb->next = ldb_free;	/* our next is old top */
   	lb->last->next = ldb_free->last = lb;	/* tell others about us */
    }
    ldb_free = lb;		/* we become the new top no matter what */
#if MULTI_LB
    lb->proc = 0;		/* not attached to any process anymore */
#endif
    lb->flags = 0;		/* no flags */
    lb->ttybf = 0;		/* no tty_buf */
}
#endif
#include "cledefault.c"

/*************************************************************************
 * Ran out of tty_buf's or led_buf's so ripple through the allocated ones
 * and deallocate any that are no longer being used. It is also called to
 * init the links in the structures.
 */
	 static int garbage_collect(oldtbp)
   	 struct tty_buf *oldtbp;
/*
 * At entry:
 *	Process context: task. NEVER call from an interrupt routine.
 *	oldtbp - ptr to tbp buffer of buffer not to put on free list
 *	tty_free points to first element in free list for tty_buf's
 *	tty_used points to first element in used list for tty_buf's
 *	ldb_free points to first element in free list for led_buf's
 * At exit:
 *	all led_buff's assigned to defunct processes are placed back in the
 *	free list. All tty_buf's that have no led_buf's assigned are
 *	placed back in the free list.
 */
{
    struct tty_buf *tbp,*nxttbp,*lasttbp;
    struct led_buf *lb,*nxtlb,*lastlb;
    int cnt;
    if (tty_used == 0 && tty_free == 0) { /* if first time through */
	lb = cle_buffers;
#if MULTI_LB
        lb->next = lb->last = lb;	/* put all led_buf's on free list */
	ldb_free = lastlb = lb++;
	for (cnt=1;cnt<MAX_LEDBUFS;++cnt,++lb) {
	    nxtlb = lastlb->next;
	    (lb->next=nxtlb)->last = (lb->last=lastlb)->next = lb;
	}
#endif
	tbp = cle_ttybuf;		/* put all tty_buf's on free list */
	tbp->next = tbp->last = tbp;
#if !(MULTI_LB)
        lb->ttybf = tbp;		/* cross link the 2 structs */
        tbp->lbtop = lb++;
#endif
	lasttbp = tbp++;
	for (cnt=1;cnt<MAX_TTYBUFS;++cnt,++tbp) {
	    nxttbp = lasttbp->next;
	    (tbp->next=nxttbp)->last = (tbp->last=lasttbp)->next = tbp;
#if !(MULTI_LB)
            lb->ttybf = tbp;		/* cross link the 2 structs */
            tbp->lbtop = lb++;
#endif
	}
        tty_free = cle_ttybuf;		/* set the top pointer */
	return;				/* done */
    }	
    if ((tbp = tty_used) == 0) return;	/* if no tty's, nothing to do */
#ifdef M_KERNEL
    do {
	lasttbp = tty_used;		/* what to stop on */
#if MULTI_LB
	if ((lb = tbp->lbtop) != 0) do {  /* if there're lb's */
	    struct led_buf *lbtop;
	    lbtop = tbp->lbtop;		/* incase the tbp->lbtop moves */
	    nxtlb = lb->next;		/* incase lb is plucked from que */
	    if (lb->ttybf == 0 || lb->proc == 0 ||
		lb->proc->p_pid != lb->pid || lb->proc->p_ppid != lb->ppid) {
	        free_lb(lb,tbp);	/* put the lb on free list */
		if (tbp->lbtop == 0) break; 	/* stop if no more */
	    }
	    lb = nxtlb;			/* move on to next member */
	} while (lb != tbp->lbtop);	/* for all members in the lb que */
#endif
	nxttbp = tbp->next;		/* point to next tty_buf */
#if MULTI_LB
	if (tbp->lbtop == 0 && tbp->f_sleep_read == 0 &&
   		(tbp->flags&TB_OPENING) == 0 &&
#else
	if (tbp->f_sleep_read == 0 && (tbp->flags&TB_OPEN) == 0 &&
#endif
   		tbp != oldtbp) {
	    if (nxttbp == tbp) {	/* if end of chain */
	        tty_used = 0;		/* no more tb's */
		nxttbp = 0;		/* stop the loop */
	        lasttbp = 0;
	    } else {
                int ospl;
	        ospl = spl6();		/* no interrupts for this */
		tbp->next->last = tbp->last; /* pluck ourself from the que */
		tbp->last->next = tbp->next;
		if (tbp == tty_used) {	/* if we're at the top, move top */
		    tty_used = tbp->next;
		}
	        splx(ospl);		/* interrupts ok now */
	    }
	    if (tty_free == 0) {	/* if the free list is empty */
		tbp->next = tbp->last = tbp; /* then we become the only member */
	    } else {			/* otherwise stick us in the que */
		struct tty_buf *tn;
		tn = tty_free->next;
		(tbp->next=tn)->last = (tbp->last=tty_free)->next = tbp;
	    }
	    tty_free = tbp;		/* we become the top no matter what */
	    tbp->flags = 0;		/* now zap any existing data in struct */
	    tbp->f_refresh = tbp->f_sleep_read = 0;
	    setup_ansi_defaults(tbp);	/* reset tbp buffer if any */
	    if (tbp->broadcast.c_cf != 0) {	/* if have a cblock */
	        struct cblock *cnxt;
   		int ospl;
   		ospl = spl6();
                while((cnxt=getcb(&tbp->broadcast)) != 0) putcf(cnxt);
   		cle_kickit(tbp->ttyp);
   		splx(ospl);
	    }
	} 
	tbp = nxttbp;			/* move to next buf */
    } while (tbp != lasttbp);		/* for all members of list */
#endif					/* M_KERNEL */
}

/********************************************************************
 * Get the next available led_buf from the freelist.
 */
	static struct led_buf *get_ledbuf(tbp)	
	struct tty_buf *tbp;
/*
 * At entry:
 *	Process context: task. Must never be called from interrupt routine.
 *	tbp - ptr to tty_buf assigned to tty struct to which led_buf is to be
 *		attached.
 * At exit:
 *	returns ptr to led_buf if one is available else returns 0.
 *	If led_buf is attached, it is placed at the head of the que;
 *	tbp->lbtop will be moved in that case. The led_buf is initialised
 *	for use. The history buffer is purged and the keydef buffer is
 *	preset to defaults.
 */
{
    struct led_buf *lb,*next,*last;
    int cnt;
    unsigned char *chr;
#if !(MULTI_LB)
    lb = tbp->lbtop;			/* there's only 1 */
#else
    if (ldb_free == 0) {		/* if no more free buffers */
	garbage_collect(tbp);	 	/* try to free up some */
	if (ldb_free == 0) return 0;	/* if still none, return empty */
    }
    lb = ldb_free;			/* pick up the one on top */
    if (lb->next == lb) {		/* if we're the only one */
	ldb_free = 0;			/* free list is now empty */
    } else {
	lb->next->last = lb->last;	/* pluck ourselves from free que */
	lb->last->next = lb->next;
	ldb_free = lb->next;		/* move free pointer */
    }
    if (tbp->lbtop == 0) {		/* if we're to be the only member */
	lb->next = lb->last = lb;	/* point to ourself */
    } else {
	next = tbp->lbtop;		/* point to new next */
	last = next->last;
	(lb->last=last)->next = (lb->next=next)->last = lb;
    }
    tbp->lbtop = lb;
    lb->ttybf = tbp;			/* connect led_buf to tty_buf */
#ifdef M_KERNEL
    lb->proc = u.u_procp;		/* save pointer to process struct */
    lb->pid = u.u_procp->p_pid;		/* and requestor's pid */
    lb->ppid = u.u_procp->p_ppid;	/* and pid of parent */
#endif
#endif
    lb->flags = (tbp->flags&TB_INSERT) ? LD_INSERT : 0;
    lb->old[0] = 1;			/* zap history buffer */
    lb->old[1] = 0;			
    lb->prmptsz = 0;			/* no prompt */
    chr = lb->old + HISTBUFSIZ;		/* zap the key def buffer */
    *--chr = 0;				/* no key defs anymore */
    lb->key = chr;
    lb->owed = 0;
    return lb;				/* done */
}

#if MULTI_LB
/********************************************************************
 * Find the led_buf in the list belonging to this process.
 */
	static struct led_buf *find_ledbuf(tbp,uproc)
	struct tty_buf *tbp;
	struct proc *uproc;
/*
 * At entry:
 *	Process context: task. Must never be called from interrupt routine.
 *	tbp - ptr to tty_buf assigned to tty struct which has led_buf que
 *	uproc - pointer to element in process table (used only to inspect
 *		the p_pid and p_ppid fields).
 * At exit:
 *	returns ptr to led_buf if one is found else returns 0.
 *	If led_buf is found, it is placed at the head of the que;
 *	tbp->lbtop may be moved in that case.
 */
{
    struct led_buf *lb,*next;
    int cont,cnt=0;
    if ((lb = tbp->lbtop) == 0) return 0;
#ifdef M_KERNEL
    do {
        cont = 0;
        next = lb->next;		/* save ptr to next */
        if (lb->proc == 0 || lb->proc->p_stat == 0) { /* purge led_bufs for... */
            if (lb == tbp->lbtop) cont = 1; /* if we're the top */
	    free_lb(lb,tbp);		/* ...defunct procs */
	    if (tbp->lbtop == 0) {
	       lb = 0;			/* there aren't anymore */
	       break;
	    }
        } else {
	    if (lb->proc == uproc) {	/* if found the one for this process */
	        if (lb->pid != uproc->p_pid || lb->ppid != uproc->p_ppid) {
	 	    free_lb(lb,tbp);	/* but process has gone defunct... */
		    lb = 0;		/* ...put it back on the freelist */
	        } else if (lb != tbp->lbtop) {	/* if not already at head of que */
		    struct led_buf *next,*last;
		    lb->last->next = lb->next;	/* pluck ourselves from the list */
		    lb->next->last = lb->last;
		    next = tbp->lbtop;		/* point to new next */
		    last = next->last;
		    (lb->last=last)->next = (lb->next=next)->last = lb;
		    tbp->lbtop = lb;		/* and we're the new top */
		}
	        return lb;
	    }
        }
        lb = next;
        ++cnt;
    } while ((cont || lb != tbp->lbtop) && cnt < MAX_TTYBUFS);
    return 0;			/* not in the list */
#else
   return &cle_buffers[0];
#endif
}
#endif			/* MULTI_LB */

/***************************************************************************
 * Get a tty_buf from the free pool.
 */
	static struct tty_buf *get_ttybuf(tp)
   	struct tty *tp;
/*
 * At entry:
 *	Process context: task. Never call this from an interrupt routine.
 *	tp - ptr to tty struct to which the tty_buf will become associated.
 * At exit:
 *	returns ptr to tty_buf or 0 if there aren't any available.
 *	tty_buf is removed from the free list and inserted into the used
 *	list which may make tty_used and tty_free change values.
 */
{
    struct tty_buf *tbp,*next,*last;
    int cnt;
    unsigned char *chr;
    if (tty_free == 0) {		/* if no more free buffers then */
	garbage_collect(tbp);		/* try to free up some */
	if (tty_free == 0) return 0;	/* if still none, give up */
    }
    tbp = tty_free;			/* take one from the top */
    if (tbp->next == tbp) {		/* if we're the last one... */
	tty_free = 0;			/* the list is now empty */
    } else {
	tbp->next->last = tbp->last;	/* extricate this one from the freelist */
	tbp->last->next = tbp->next;
        tty_free = tbp->next;		/* move free pointer */
    }
    tbp->ttyp = tp;			/* connect tty_buf to device */
    tbp->f_refresh = tbp->f_sleep_read = 0;
#if MULTI_LB
    tbp->lbtop = 0;			/* no lb buffer assigned */
#else
    get_ledbuf(tbp);			/* init the attached lb */
#endif
    next = tty_used;
    if (next == 0) {			/* if we're the first one used */
	tbp->next = tbp->last = tbp;	/* point to ourself */
#ifdef M_KERNEL
    } else {
	int ospl;
	ospl = spl6();			/* no interrupts */
	last = next->last;
	(tbp->last=last)->next = (tbp->next=next)->last = tbp;
	splx(ospl);			/* interrupts ok now */
#endif
    }
/*
 * The following sets up the default insert/overstrike mode
 */
    tbp->flags = TB_INSERT;			/* default to insert mode */
/* 
 * Setup the default ansi strings to output to the terminal for various operations
 */
    setup_ansi_defaults(tbp);
/*
 * The following init's cross connect the input key to the desired edit function
 */
    setup_key_defaults(tbp);
/*
 * End of function setup 
 */
    tty_used = tbp;				/* we become the new head of the que */
    return tbp;					/* done */
}

/*************************************************************************
 * Find a tty_buf that's attached to a tty struct and move it to the head
 * of the que if it's in the list.
 */
	static struct tty_buf *find_ttybuf(tp)
	struct tty *tp;
/*
 * At entry:
 *	Process context: task. Must not be called from interrupt.
 *	tp - ptr to tty struct to match
 * At exit:
 *	returns ptr to tty_buf or 0 if none found. Does not modify the
 *	contents of any structures, so it is re-entrant and interruptable.
 */
{
    int cnt=0;
    struct tty_buf *tbp,*next,*last;
    if ((tbp=tty_used) == 0) return 0;	/* not there */
    do {
        if (tbp->ttyp == tp) {		/* found it. Move ourselves to head */
#ifdef M_KERNEL
	    if (tbp != tty_used) {	/* if not already there */
		int ospl;
		ospl = spl6();
		tbp->next->last = tbp->last; /* unque us */
		tbp->last->next = tbp->next;
		next = tty_used;	/* get ptr to next and prev */
		last = next->last;
		(tbp->last=last)->next = (tbp->next=next)->last = tbp;
		tty_used = tbp;		/* move this too */
		splx(ospl);
	    }
#endif
	    return tbp;
	}
	tbp = tbp->next;		/* loop */
        ++cnt;
    } while ((tbp != tty_used) && cnt < MAX_TTYBUFS);	/* through the whole list */
    return 0;				/* not there */
}

/**************************************************************************
 * The routines cleopen, cleclose, cleread, clewrite and cleioctl are
 * called by the kernel (via a dispatch through the linesw array) and are
 * all executed at process task time. The routines cleinput and cleouput
 * are interrupt routines. Except for cleinput and cleioctl all the routines
 * have the same interface: a pointer to the tty struct assigned to the
 * real or pseudo terminal. cleinput has an extra flag argument which
 * indicates whether the input character is real or the result of the 
 * terminal sending a break. cleioctl has an extra argument that has the
 * function code the ioctl is to do.
 **************************************************************************/

/**************************************************************************
 * Send saved broadcast message to terminal.
 */
      static int send_brdcst(tbp,clr_flg)
      struct tty_buf *tbp;
      int clr_flg;
/*
 * At entry:
 *	Process context: task.
 *	tbp - ptr to tty_buf which contains the message
 *	clr_flg - true if the message line is to be precleared
 * At exit:
 *	the cblock(s) holding the message are moved from the clist in tty_buf
 *	to the t_outq clist.
 */
{
#ifdef M_KERNEL
    int ospl;
    unsigned char c;
    struct cblock *bp;
    struct clist *bl,*tpc;
    tpc = &tbp->ttyp->t_outq;
    bl = &tbp->broadcast;
    if (clr_flg) cle_puts(tbp->ansi[ANSI_CLRLINE],tbp->ttyp); /* preclear the current line */
    ospl = spl6();		/* no interrupts for the following */
    while(1) {
        bp = getcb(bl);		/* get next cblock from broadcast */
        if (bp == 0) break;	/* if 0, done */
        putcb(bp,tpc);		/* stick it on the t_outq */
    }
    cle_kickit(tbp->ttyp);
    splx(ospl);			/* interrupts ok now */
#endif
}

/***************************************************************************
 * Open line discpline
 */
	static struct tty_buf *open_it(tbp,td)
	struct tty_buf *tbp;
	struct tty *td;
/*
 * At entry:
 *	tbp - ptr to tty_buf to open (or 0 if not preassigned)
 *	td - ptr to tty struct  to open
 */
{
    int flag;
#ifdef M_KERNEL
    if (tbp == 0) {
	garbage_collect();		/* free up some space */
	tbp = get_ttybuf(td);		/* get a tty_buf */
        flag = 1;
    } else {
        flag = ((tbp->flags&TB_OPEN) == 0);	/* true if not currently open */
    }
    if (tbp != 0) {
	tbp->flags |= TB_OPEN|TB_OPENING;	/* we're open */
	if (flag) {
	    show_pid(1," started by process ",td);
	    cle_puts(tbp->ansi[ANSI_SETUP],td);
	}
    } else {
	if (flag) {
	    cle_puts("\rNo buffers available to start cled\r\n",td);
	    u.u_error = ERR_NOTTYBUF;	/* return with error */
	}
    }
    if (flag) cle_kickit(td);
#endif
    return tbp;
}

/**************************************************************************
 * Open the line discipline. This procedure is called by kernel code when
 * the line discipline is selected. I haven't yet determined what exactly
 * the open is supposed to do, but since cled uses discipline 0, if IT (ld0)
 * isn't opened too, very strange terminal behavior results.
 */
      int cleopen(tp)
      struct tty *tp;
/*
 * At entry:
 *	tp - ptr to tty struct
 *	process context: task.
 * At exit:
 *	discipline 0 is opened
 */
{
#ifdef M_KERNEL
    (*linesw[0].l_open)(tp);
    open_it(find_ttybuf(tp),tp);
#endif
    return (1);
}

/***************************************************************************
 * Close the line discpline
 */
	static int close_it(tbp,td)
	struct tty_buf *tbp;
	struct tty *td;
/*
 * At entry:
 *	tbp - ptr to tty_buf to close (or 0 if not preassigned)
 *	td - ptr to tty struct  to open
 */
{
#ifdef M_KERNEL
    if (tbp != 0) {			/* if there's a tbp */
        int ospl;
	if (td->t_state&ISOPEN) {
	   show_pid(0,"\rcled stopped by process ",td);
	   cle_kickit(td);
	}
	if (tbp->f_sleep_read) {	/* and sleeping */
	    wakeup(tbp);		/* wakeup the sleepers */
	    tbp->f_sleep_read = 0;
            if (td->t_state&ISOPEN) tbp->flags |= TB_FLUSHIT;
	}
	ospl = spl6();
	tbp->flags &= ~(TB_OPEN|TB_OPENING); /* not open anymore */
	splx(ospl);
    }
#endif
}

/**************************************************************************
 * Close the line discipline. This procedure is called by kernel code when
 * the line discipline is deselected. I haven't yet determined what exactly
 * the close is supposed to do, but a call to close discipline 0 is done
 * because it apparently needs it.
 */
      int cleclose(tp)
      struct tty *tp;
/*
 * At entry:
 *	tp - ptr to tty struct
 *	process context: task.
 * At exit:
 *	discipline 0 is closed
 */
{
#ifdef M_KERNEL
    (*tp->t_proc)(tp,T_RESUME);		/* make sure output is running */
    close_it(find_ttybuf(tp),tp);
    delay(HZ);				/* wait 1 second */
    ttyflush(tp,FWRITE|FREAD);		/* then flush the ques */
    (*linesw[0].l_close)(tp);
#endif
    return (1);
}

#ifdef M_KERNEL
/************************************************************************
 * read timeout routine. This is a a kludge cuz I can't figure out who's
 * zapping the tty struct out from under cled. It usually happens after
 * the cleread routine has gone to sleep. It can be forced, however by
 * some other process intentionally changing the line number or other
 * tty flags while a read is in progress. This routine helps correct
 * the sitiuation.
 */
      static int read_timeout(arg)
      struct tty_buf *arg;
/*
 * At entry:
 *	arg - ptr to the tty_buf belonging to the process doing the read
 * At exit:
 *	TB_TIMEOUT set in the tty flags and a wakeup is delivered.
 */
{
    if (arg->f_sleep_read) wakeup(arg);
    arg->f_sleep_read = 0;
    return;
}

/**********************************************************************
 * Announce that's there's no room at the inn
 */
	 static int no_room(tp,typ)
	 struct tty *tp;
	 char *typ;
/*
 * At entry:
 *	tp - ptr to tty struct
 *	typ - ascii string describing buffer type that we're out of
 * At exit:
 *	message output to the terminal
 *	line discipline reset to ld 0
 */
{
     cle_puts("\rSorry, not enough ",tp);
     cle_puts(typ,tp);
     cle_puts(" buffers to run cled at this time.\r\n",tp);
     tp->t_line = 0;		/* switch to line 0 */
     (*linesw[0].l_read)(tp);	/* use ld0's read */
     return 1;
}
#endif

/************************************************************************
 * Read a line from the terminal. This routine exits when the user types
 * the specified eol character (normally a \r).
 */
      int cleread(tp)		/* called by the terminal driver */
      struct tty *tp;
/*
 * At entry:
 *	Process context: task.
 *	tp - ptr to tty struct
 * At exit:
 *	process sleeps until user types one of an EOL, an EOF, a QUIT or
 *	an INTR character (normally an \r, ^D, DEL and ^C characters
 *	respectively). The line of text input from terminal is moved
 *	to user's buffer as specified by u.u_count and u.u_base. An EOF
 *	results in 0 chars being returned. This routine will not exit
 *	normally if an interrupt or quit character is typed (the kernel
 *	takes control via the signal and will cancel the I/O request
 *	without this routine going through its normal exit sequence).
 *	If the terminal has been set to "raw" mode, this read passes
 *	control to discipline 0, otherwise the line editing functions
 *	of cled become active while the line of input is being typed.
 */
{
     struct led_buf *lb;
     struct tty_buf *tbp;
     unsigned char *cp;
     int c,len,time_id;
 
     tbp = find_ttybuf(tp);		/* get tty buffer */
#ifdef M_KERNEL
     if (tbp == 0) return no_room(tp,"tty");
     if (u.u_count == 0 ||
   	   ((tp->t_lflag&(ICANON|ECHO|ECHOE|ECHOK)) !=
   			 (ICANON|ECHO|ECHOE|ECHOK))) {
         if (tbp != 0) tbp->flags |= TB_NOLINE;	/* reading without ld */
         (*linesw[0].l_read)(tp);	/* use ld0's read */
         return 1;
     }
     if ((tbp->flags&TB_OPEN) == 0) open_it(tbp,tp);
#endif
#if MULTI_LB
     lb = find_ledbuf(tbp,u.u_procp);	/* get associated led_buf */
     if (lb == 0) lb = get_ledbuf(tbp);	/* get a new one */
#else
     lb = tbp->lbtop;
#endif
     if (tbp->broadcast.c_cc != 0) {
         send_brdcst(tbp,0);
         cle_puts("\r\n",tp);
         tbp->f_refresh = 1;		/* reprint the prompt if there is one */
     }
#ifdef M_KERNEL
     if (lb == 0) {
	 close_it(tbp,tp);
	 return no_room(tp,"led");
     }
#endif
     tbp->flags &= ~(TB_NOLINE|TB_OPENING); /* reading with line discipline */
#ifdef M_KERNEL
     if (lb->owed != 0) {		/* if still owe data from last time */
	 len = lb->lcurs-lb->owed;	/* how much data left to send */
	 if (len > 0) {			/* if valid */
	    if (len > u.u_count) len = u.u_count; /* only as much as asked for */
	    copyout(lb->owed,u.u_base,len); /* give 'em what's left */
	    lb->owed += len;
	    u.u_base += len;
	    u.u_count -= len;
	    if (lb->owed >= lb->lcurs) lb->owed = 0;	/* owe no more */
	    return;			/* keep going until all given */
	 }
	 lb->owed = 0;		/* owe no more */
     }
#endif
     lb->maxlin = COMBUFSIZ-1;		/* max length of command line (cannot be > 255) */
     lb->end_posn = lb->maxlin - 1;	/* set the max pointer */
     lb->lcurs = lb->buf;		/* set the left side ptrs */
     lb->rcurs = lb->bufend = lb->buf + lb->end_posn; /* and right side ptrs */
     lb->state = NORMAL;		/* start out normal */
     lb->oldndx = 0;			/* reset the index to the history file */
     lb->oldmatlen = 0;			/* for match history */
     lb->flags &= ~(LD_DONE|LD_QUIT|LD_INTR|LD_EOF|LD_BACKUP|LD_INSERT);
     lb->flags |= (LD_DIRTY);		/* buffer is dirty and insert mode */
     if (tbp->flags&TB_INSERT) lb->flags |= LD_INSERT; 	/* set default mode */
     tbp->flags |= TB_READING;		/* tell top level someone is reading */
     lb->defkey = 0;			/* not defining a buffer */
     lb->c_posn = 0;			/* at left side */
     *lb->lcurs = *lb->rcurs = 0;	/* put nulls at both ends of the buffer */
#ifdef M_KERNEL
     tbp->iflag = tp->t_iflag;
     tbp->oflag = tp->t_oflag;
     tbp->lflag = tp->t_lflag;
     tbp->cflag = tp->t_cflag;
     for (c=0;c<NCC+2;++c) tbp->cc[c] = tp->t_cc[c];
     while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING) != 0) {
        cle_kickit(tp);			/* make sure output is running */
        delay(HZ/10);			/* wait for output to clear */
     }
     if (tbp->f_refresh) {		/* if we start with refresh */
	tbp->f_refresh = 0;
	reprint(lb);			/* then put up the prompt et al */
	cle_kickit(tp);			/* make sure output is running */
     }
#endif
     while ((lb->flags&LD_DONE) == 0) {	/* loop until a whole line is typed in */
#ifdef M_KERNEL
        int ospl;
        ospl = spl6();			/* disable tt interupts during rbi test */
        if (tp->t_rawq.c_cc == 0) {	/* if nothing in the input */
	    if (tbp->f_refresh) {	/* got a punch through? */
	       tbp->f_refresh = 0;	/* yep, reset it */
	       splx(ospl);		/* re-enable interrupts */
	       reprint(lb);		/* ...refresh the screen */
	       cle_kickit(tp);		/* ...kick start the output */
	       continue;		/* see if more input showed up */
	    }   
	    if ((tbp->flags&TB_OPEN) == 0) {	/* we're no longer using this ld */
		lb->flags |= LD_DONE|LD_EOF;	/* signal eof */
   		cle_puts("\r\nTrying to cleread while cled turned off\r\n",tp);
		break;
	    }
	    if (tp->t_line != our_lineno || 
   	   	((tp->t_lflag&(ICANON|ECHO|ECHOE|ECHOK)) != (ICANON|ECHO|ECHOE|ECHOK))) {
		cle_puts("\r\n\007cled warning: tty struct has been zapped. Reseting it.\r\n",tp);
		tp->t_iflag = tbp->iflag;
		tp->t_oflag = tbp->oflag;
		tp->t_lflag = tbp->lflag;
		tp->t_cflag = tbp->cflag;
		tp->t_line = our_lineno;
		for (c=0;c<NCC+2;++c) tp->t_cc[c] = tbp->cc[c];
     		tp->t_state |= ISOPEN;
		tbp->f_refresh = 1;
		continue;
	    }
	    time_id = timeout(read_timeout,tbp,HZ*15);	/* set 15 second timeout */
 	    tbp->f_sleep_read = 1;	/* signal we're asleep */
 	    if (sleep(tbp,PZERO+8|PCATCH)) {	/* sleep for awhile */
	       untimeout(time_id);	/* cancel timeout */
	       u.u_error = EINTR;	/* got an attention */
	       return (-1);		/* exit with an error */
	    }
	    untimeout(time_id);		/* cancel the timeout */
	    splx(ospl);			/* just in case we come back at spl6 */
	    while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING) != 0) {
		cle_kickit(tp);		/* make sure output is running */
	        delay(HZ/10);		/* wait for it to clear */
	    }
	    if ((tbp->flags&TB_FLUSHIT) != 0) {
	       eol(lb);		/* goto eol */
	       d_bol(lb);	/* delete to bol */
	       ospl = spl6();
	       tbp->flags &= ~TB_FLUSHIT;
	       tbp->f_refresh = 1;
	       splx(ospl);
	       if ((tbp->flags&TB_OPEN) == 0) break;
	    }
	    continue;
        }
        splx(ospl);		/* reset our priority */
	c = getc(&tp->t_rawq);	/* pickup the next char */
#else
        c = cle_getc(lb);
#endif
	if (lb->state == NORMAL && c != 0) {
	    if (c == tp->t_cc[VEOF]) {	/* got an EOF? */
		lb->flags |= LD_EOF;	/* say we got an EOF */
                lb->state = NCC_SPC|VEOL; /* and eol */
		c = 0;
	    } else if (c == tp->t_cc[VERASE]) {	 /* erase? */
		lb->state = NCC_SPC|VERASE; /* signal special mode */
		c = 0;
	    } else if (c == tp->t_cc[VKILL]) { /* line kill? */
		lb->state = NCC_SPC|VKILL;
		c = 0;
	    } else if ((tp->t_cc[VEOL] == 0 && c == CR) || 
		     (c == tp->t_cc[VEOL])) { /* end of line? */
		lb->state = NCC_SPC|VEOL;
		c = 0;
	    } 
       }
       lb->c = c;			/* pass the char */
       parse_it(lb);			/* parse what we've got */
#ifdef M_KERNEL
       cle_kickit(tp);
#endif
    }					/* for all input chars */
    cp = lb->lcurs;			/* point to end of command line */
    if ((lb->flags&LD_EOF) == 0) {
	*cp++ = '\n';			/* stuff in an EOL */
    	lb->lcurs = cp;
    }
    len = cp-lb->buf;
    tbp->flags &= ~TB_READING;		/* no longer reading */
#ifdef M_KERNEL
    if (len != 0) {
       if (len > u.u_count) len = u.u_count;
       copyout(lb->buf,u.u_base,len);
       u.u_base += len;
       u.u_count -= len;
       cle_puts("\r\n",tp);
    } else {
       cle_puts(tbp->ansi[ANSI_MSGEOF],tp);
    }
    if (tp->t_delct > 0) --tp->t_delct;	/* count down the delimiter */
    if (tbp->broadcast.c_cc != 0) {	/* got a broadcast message */
        send_brdcst(tbp,0);		/* blast the broadcast message */
        cle_puts("\r\n",tp);		/* follow it with a \n */
    }
    cle_kickit(tp);			/* kick start the output */
#else
    strncpy(u.u_base,lb->buf,len);
    *(u.u_base+len) = 0;
#endif
    if (lb->buf+len >= lb->lcurs) {	/* if he got all we had */
       lb->owed = (unsigned char *)0;
    } else {
       lb->owed = lb->buf+len;		/* else point to what to give 'em next */
    }
    lb->prmptsz = 0;			/* kill any existing prompt */
    lb->prmpt[0] = 0;
    return 1;
}

#ifdef M_KERNEL
/************************************************************************
 * Kick start the output. This routine is called whenever there is data
 * in the t_outq buffer to make sure that it gets sent to the terminal.
 */
      static int cle_kickit(tp)
      struct tty *tp;
/*
 * At entry:
 *	Process context: Task or Interrupt. May be called from either.
 *	tp - ptr to tty struct
 * At exit:
 *	If data present in t_outq and output not already running, then a
 *	call to the terminal driver processor routine (t_proc) with the
 *	output option selected is made which will cause data to be moved
 *	from the t_outq clist to the t_obuf output array for subsequent
 *	output to the hardware. 
 */
{
    int ospl;
    ospl = spl6();		/* no interrupts for the next test */
    if (tp->t_outq.c_cc != 0) {	/* anything in the output que? */
       if ((tp->t_state&(BUSY|TIMEOUT|TTSTOP)) == 0 ||
   		tp->t_tbuf.c_count == 0) { /* and output not already busy */
	  splx(ospl);		/* interrupts ok now */
	  (*tp->t_proc)(tp,T_OUTPUT); /* kick start the output */
       }
    }
    splx(ospl);			/* reset the priority */
}

/**************************************************************************
 * Put a character in the output que for subsequent output to the terminal
 */
      static int cle_putc(c,tp)
      unsigned char c;
      struct tty *tp;
/*
 * At entry:
 *	Process context: Task or Interrupt.
 *	c - char to output
 *	tp - ptr to tty struct
 * At exit:
 *	character is placed in the t_outq clist. If there's no more room,
 *	it is discarded with no error message.
 */
{
    putc(c,&tp->t_outq);
}

/**************************************************************************
 * Put a null terminated string of characters in the output que for subsequent
 * output to the terminal.
 */
      static int cle_puts(s,tp)
      unsigned char *s;
      struct tty *tp;
/*
 * At entry:
 *	Process context: Task or Interrupt.
 *	s - ptr to null terminated string to output
 *	tp - ptr to tty struct
 * At exit:
 *	characters are placed in the t_outq clist. If there's no room for
 * 	the whole message, that that won't fit is discarded with no error.
 */
{
    register unsigned char *s1 = s;
    struct clist dumcl,*clp;
    struct cblock *srcp;
    int ospl,cnt;
    if (s1 == 0 || *s1 == 0) return;	/* skip null msgs */
    while(*s1++);			/* skip to end of string */
    cnt = s1-s-1;			/* compute length of string */
    dumcl.c_cc = 0;			/* init our dummy clist */
    dumcl.c_cf = dumcl.c_cl = 0;
    clp = &tp->t_outq;			/* ptr to outq clist */
    ospl = spl6();			/* book says hafta call at spl6() */
    putcbp(&dumcl,s,cnt);		/* put msg into dummy clist */
    while((srcp = getcb(&dumcl)) != 0) putcb(srcp,clp); /* copy to outq */
    splx(ospl);				/* interrupts ok now */
    return;
}

/*************************************************************************
 * Input interrupt routine. This routine is called after n characters have
 * been placed in the interrupt holding buffer (t_rbuf) and/or a certain
 * time has elapsed since the last input interrupt occurred (This technique
 * tends to reduce the CPU load somewhat by bunching input character
 * processing on dumb terminal ports).
 */
      int cleinput(td,bflg)
      struct tty *td;
      int bflg;
/*
 * At entry:
 *	Process context: Interrupt
 *	td - ptr to tty struct
 *	bflg - not 0 if interrupt due to a BREAK, else 0
 * At exit:
 *	data in the t_rbuf buffer has been moved to the t_rawq clist.
 *	If the terminal is not in raw mode, then checks for the INTR
 *	and QUIT input chars were made and signals sent if so found.
 *	A wakeup() has been issued to any processes waiting for input
 *	from this port.
 */
{
    int i,indx,ospl;
    unsigned char c,*cp,*msg;
    struct led_buf *lb;
    struct tty_buf *tbp;
    tbp = tty_used;		/* get ptr to top of tty_buf list */
    i = 0;
    if (tbp != 0) do {		/* find ptr belonging to this port */
	if (tbp->ttyp == td) break;
	tbp = tbp->next;
        ++i;
    } while ((tbp != tty_used) && i < MAX_TTYBUFS);
    if ((td->t_lflag&(ICANON|ECHO|ECHOE|ECHOK)) != (ICANON|ECHO|ECHOE|ECHOK) ||
		tbp == 0 || tbp->ttyp != td ||
   		(tbp->ttyp == td && (tbp->flags&TB_NOLINE) != 0)) {
   		/* if terminal in "raw mode" or there's no tb ptr for it or
   		   the tb indicates to use no discipline then... */
        (*linesw[0].l_input)(td,bflg);	/* ...use normal mode */
        return;
    }
    if (bflg == L_BREAK) {		/* if got here due to a BREAK */
       if ((td->t_lflag&ISIG) != 0 && (td->t_iflag&BRKINT) != 0) {
	   cp = &c;			/* if ISIG and BRKINT enabled */
	   c = td->t_cc[VINTR];		/* pretend we got an INTR char */
	   i = 1;			/* only 1 char */
       } else {
	   return;			/* else ignore it */
       }
    } else {
       if (td->t_rbuf.c_ptr == (unsigned char *)0 ||
	   td->t_rbuf.c_count >= td->t_rbuf.c_size) {
	  return;
       }
       i = td->t_rbuf.c_size-td->t_rbuf.c_count; 	/* compute byte count again */
       cp = td->t_rbuf.c_ptr;			/* point to first byte in string */
       td->t_rbuf.c_count = td->t_rbuf.c_size;	/* reset the length */
    }
    for (;i>0; --i) {			/* move all the chars */
       int esc;
       if ((esc = td->t_state&CLESC) != 0) { /* remember whether this is escaped */
	  td->t_state &= ~CLESC;	/* clear it for next time */
       }
       c = *cp++;			/* get a copy of the char */
       if (esc == 0) {
	  int quit,intr,swtch;
	  quit = td->t_cc[VQUIT];
	  intr = td->t_cc[VINTR];
	  swtch = td->t_cc[VSWTCH];
	  if (c == quit || c == intr) { 	/* intr or quit? */
	     msg = (c == quit) ? tbp->ansi[ANSI_MSGQUIT] : tbp->ansi[ANSI_MSGINTR];
	     if ((td->t_lflag&NOFLSH) == 0) ttyflush(td,FWRITE|FREAD);
	     while (*msg) putc(*msg++,&td->t_outq);
	     cle_kickit(td);
	     if (tbp->f_sleep_read) {
		tbp->f_sleep_read = 0;
		wakeup(tbp);
	     }
   	     tbp->flags |= TB_FLUSHIT;
	     signal(td->t_pgrp,(c == quit) ? SIGQUIT : SIGINT);	/* signal an interrupt to process */
	     break;			/* eat the rest of the input */
	  }
	  if (c != 0 && c == swtch) {
	     if ((*td->t_proc)(td,T_SWTCH) != T_SWTCH) { /* go to shl */
		return;			/* eat rest of input */
	     }
	  }
       }
       if (c < 0x20 && tbp->keymap[c] == CLEFUN_PURGE) {
	   ttyflush(td,FREAD);
	   if (tbp->f_sleep_read) {
	       tbp->flags |= TB_FLUSHIT;
	       break;
	   }
       }
       if (td->t_rawq.c_cc > 253 || putc(c,&td->t_rawq) == -1) { /* move the char */
	   tbp->flags |= TB_OVERUN;	/* signal we got an overrun */
           cle_putc(BEL,td);
       } else {
	   if (esc == 0) {
	      if (c < 0x20 && tbp->keymap[c] == CLEFUN_ESCAPE) {	/* if this is an escape code */
		  td->t_state |= CLESC;		/* signal last char is an escape */
	      } else if ( c != 0 &&		/* null is not a delimiter */
		  	 (c == td->t_cc[VEOL] || /* if user's spec'd delimiters */
		    	  c == td->t_cc[VEOL2] ||
		    	  c == td->t_cc[VEOF] || /* or an EOF char */
		   	 (c < 0x20 && tbp->keymap[c] == CLEFUN_NEWLINE))) { /* or mapped */
		 ++td->t_delct;			/* count it so rdchk() works */
	      }
	   }
       }
    }
    if (tbp->f_sleep_read) {
       tbp->f_sleep_read = 0;
       wakeup(tbp);
    }
#ifdef M_UNIX
    if (td->t_state&IASLP) {		/* if by some chance, we're turned on while */
	ttiwake(td);			/* LD 0 is reading, wake it up too */
    }
#endif
    return;
}

static int show_pid(disp,str,td)
int disp;
char *str;
struct tty *td;
{
    unsigned char tmp[10],*s;
    if (disp != 0) {
	cle_puts("\rcled version ",td);
	cle_puts(VERSION,td);
    }
    cle_puts(str,td);
    s = itoa(u.u_procp->p_pid,tmp,10);
    *s = 0;
    cle_puts(tmp,td);
    cle_puts(" (",td);
    s = itoa(u.u_procp->p_ppid,tmp,10);
    *s = 0;
    cle_puts(tmp,td);
    cle_puts(")\r\n",td);
    return;
}

/*************************************************************************
 * Line discipline IOCTL routine. 
 */
	cleioctl(td,f1,arg,mode)
	struct tty *td;
	int f1,mode;
        faddr_t arg;
/*
 * At entry:
 *	Process context: task.
 *	td - ptr to tty struct
 *	f1 - function to perform
 * At exit:
 *	ioctl function is performed
 */
{
    struct tty_buf *tbp;
    struct led_buf *lb;
    tbp = find_ttybuf(td);		/* see if we've a tty_buf assigned */
    if (tbp != 0 && ((tbp->flags&(TB_READING|TB_WRITING)) != 0 || tbp->f_sleep_read != 0)) {
	cle_puts("\r\ncled warning: ioctl issued while terminal busy. stty bits may be zapped\r\n",td);
        cle_kickit(td);			/* make sure output is running */
    }
    if (f1 >= LDGETS) {			/* if it's ours */
	garbage_collect(tbp);		/* free up some space */
	if (tbp == 0) tbp = get_ttybuf(td);	/* assign one if none present */
	if (tbp == 0) {			/* no free buffers */
	    u.u_error = ERR_NOTTYBUF;	/* no free space error */
	    return;
	}
#if MULTI_LB
	if ((lb=tbp->lbtop) != 0) {	/* if there's a chain of led_bufs */
	    struct led_buf *us=0,*parent=0;
	    do {
		if (u.u_procp->p_ppid == lb->pid) parent = lb; /* save parent's lb */
		if (u.u_procp->p_pid == lb->pid) us = lb;      /* save our lb */
	    } while ((lb=lb->next) != tbp->lbtop);
	    if (us != 0) lb = us;		/* use ours if we have one */
	    else if (parent != 0) lb = parent;	/* use parent's if it has one */
	    else lb = 0;			/* else there aren't any */
	}
#else
        lb = tbp->lbtop;
#endif
	switch (f1) {
	    struct set_key sk;
	    case LDGETHB: {			/* return history buffer (if present) */
		if (lb == 0) {
		    u.u_error = ERR_NOLBASS;
		    return;
		}
		copyout(lb->old,arg,HISTBUFSIZ);
		return;
	    }
	    case LDGETBF: {			/* return the keydef buffer */
		char cnt,len;
		faddr_t outp;
		sk.modes = 0;
		if ((tbp->flags&TB_INSERT) != 0) {
		    sk.modes |= CLEMODE_INSERT;
		} else {
		    sk.modes |= CLEMODE_OVER;
		}
		if ((tbp->flags&TB_132) != 0) {
		    sk.modes |= CLEMODE_132;
		} else {
		    sk.modes |= CLEMODE_80;
		}
		sk.kdbuf_len = CLEKEY_MAX;	/* gets all the keys */
		copyout(tbp->keymap,arg+sizeof(sk),CLEKEY_MAX);
		outp = arg+sizeof(sk)+CLEKEY_MAX;
		for (cnt = 0;cnt < ANSI_COUNT; ++cnt) {
		    char *s;
		    copyout(&cnt,outp++,1);	/* pass the string # */
		    s = tbp->ansi[cnt];		/* point to string */
		    while(*s++);		/* skip to end */
		    len = s-tbp->ansi[cnt];	/* compute length including null */
		    copyout(tbp->ansi[cnt],outp,len); /* send it to user */
		    outp += len;		/* move his pointer */
		}
		sk.ansibuf_len = outp-(arg+sizeof(sk)+CLEKEY_MAX);
		copyout(&sk,arg,sizeof(sk));
		return;
	    }
	    case LDSETBF: {			/* set keys, modes and ansi strings */
		int oldflag;
		copyin(arg,&sk,sizeof(sk));
		oldflag = tbp->flags;
		if (sk.modes&CLEMODE_INSERT) tbp->flags |= TB_INSERT;
		else if (sk.modes&CLEMODE_OVER) tbp->flags &= ~TB_INSERT;
		if (sk.modes&CLEMODE_80) tbp->flags &= ~TB_132;
		else if (sk.modes&CLEMODE_132) tbp->flags |= TB_132;
		if (((oldflag^tbp->flags)&TB_132) != 0) {
		    setcol_width(tbp->flags&TB_132,tbp);
		    cle_kickit(tbp->ttyp);
		}
		if (sk.kdbuf_len > CLEKEY_MAX) {
		    sk.kdbuf_len = CLEKEY_MAX;
		    copyout(&sk,arg,sizeof(sk));
		    u.u_error = ERR_BADPARAM;
		    return;
		}
		if (sk.kdbuf_len > 0) {
#if _SPTALLOC
		    unsigned char *tmp,*kp;
#else
		    unsigned char tmp[100],*kp;
#endif
		    int cnt,size;
                    size = sk.kdbuf_len*2;
#if _SPTALLOC
		    kp = tmp = (unsigned char *)Sptalloc(size);
#else
		    if (size > sizeof(tmp)) {
		       u.u_error = ERR_BADPARAM;
		       return;
		    }
		    kp = tmp;
#endif
		    copyin(arg+sizeof(sk),tmp,size);
		    for (cnt=0;cnt<sk.kdbuf_len;++cnt) {
			int key,func;
			key = *kp++;
			func = *kp++;
			if (key >= CLEKEY_MAX || func >= CLEFUN_MAX) {
#if _SPTALLOC
			    Sptfree(tmp,size);
#endif
			    sk.kdbuf_len = cnt;
			    copyout(&sk,arg,sizeof(sk));
			    u.u_error = ERR_BADPARAM;
			    return;
			}
			tbp->keymap[key] = func;
		    }
#if _SPTALLOC
		    Sptfree(tmp,size);
#endif
		}
		if (sk.ansibuf_len > 0) {	/* setting some ansi defaults */
		    setup_ansi_defaults(tbp);	/* reset all the defaults */
		    if (sk.ansibuf_len > 1) {	/* if there's at least one string */
			char *s;
			int nfg = 0;
#if _SPTALLOC
			s = tbp->tmpbuf = (unsigned char *)Sptalloc(sk.ansibuf_len);
#else
	                s = tbp->tmpbuf;
                        if (sk.ansibuf_len > ANSISIZE) {
			    sk.ansibuf_len = ANSISIZE;
			    copyout(&sk,arg,sizeof(sk));
			    u.u_error = ERR_BADPARAM;
			    return;
			}
#endif
			tbp->tmpsize = sk.ansibuf_len;
			copyin(arg+sizeof(sk)+sk.kdbuf_len*2,s,tbp->tmpsize);
			while (s < tbp->tmpbuf+tbp->tmpsize) {
			    unsigned char *ap;
			    int str;
			    str = *s++;		/* get string # */
			    if (str >= ANSI_COUNT) { /* if nfg */
				nfg = 1;
				break;
			    }
			    ap = s;
			    while (*ap && ap < tbp->tmpbuf+tbp->tmpsize) ++ap;
			    if (*ap != 0) {
				nfg = 1;
				break;
			    }
			    tbp->ansi[str] = s;
			    s = ap+1;
			}
			if (nfg) {
			    sk.ansibuf_len = s - tbp->tmpbuf;
			    copyout(&sk,arg,sizeof(sk));
			    u.u_error = ERR_BADPARAM;
			    return;
			}
		    }
		}
		return;
	    }
	}
    } else {
        if (f1 == LDCLOSE) {		/* if closing */
	    close_it(tbp,td);
        } else if (f1 == LDOPEN || f1 == LDCHG) {
	    open_it(tbp,td);
	}
        (*linesw[0].l_ioctl)(td,f1,arg,mode); /* call ld 0 */
    }
    cle_kickit(td);			/* make sure output is running */
}

/***************************************************************************
 * Write some text to the terminal but catch any trailing data into a prompt
 * buffer. This routine is executed when no read is in progress on the
 * terminal, an lb buffer is assigned to the terminal and a write comes
 * through.
 */
   	static int catch_prompt(tbp,lb)
   	struct tty_buf *tbp;
   	struct led_buf *lb;
/*
 * At entry:
 *	tbp - ptr to tty_buf assigned to terminal
 *	lb - ptr to led_buf assigned to terminal
 *	u.u_base - ptr to message (u.u_count has length of message)
 * At exit:
 *	the text from the trailing \n (if any) of the message has been copied to
 *	the prompt buffer in the led_buf. If the last char of the message is
 *	a \n, then prompt buffer is left empty. If there are no \n's in the
 *	message, then the whole message is appended to any existing data in
 *	the prompt buffer. Chars are removed from the beginning of the buffer
 *	if the length of the new message exceeds the PRMPTBFSIZ parameter.
 */
{
    register unsigned char *dst,*src;
    register int len;   
    int oldlen;
    unsigned char c,*temp;
    if (tbp->broadcast.c_cc != 0) {
	send_brdcst(tbp,1);		/* send accum broadcast to terminal */
    }
    copyin(u.u_base+u.u_count-1,&c,1);	/* pickup the last byte */
    if (c == '\n') {			/* if last char is a \n */
	lb->prmptsz = 0;		/* stomp on any existing prompt */
	lb->prmpt[0] = 0;		/* make sure it is null terminated */
    } else {				/* else capture prompt */
#if _SPTALLOC
        unsigned char *temp;
#else
        unsigned char temp[PROMPTBFSIZ];
#endif
	len = PROMPTBFSIZ-1;		/* assume max length */
	if (len > u.u_count) len = u.u_count;	/* oops...not so much */
	oldlen = len;
#if _SPTALLOC
	temp = (unsigned char *)Sptalloc(oldlen+1);	/* pick up some temp space */
#endif
	copyin(u.u_base+(u.u_count-len),temp,len);	/* get user's data */
	src = temp+len;			/* point to end */
	*src = 0;			/* null terminate it */
	for (;len > 0; --len) {		/* look for cr/lf */
	    c = *--src;			/* from the back to the front */
	    if (c == CR || c == LF) {
		++src;			/* found one, it stays with... */
		break;			/* ...old message */
	    }
	}
	if (len != 0 || oldlen == PROMPTBFSIZ-1) { /* if crlf's in input string... */
	    lb->prmptsz = 0;		/* ...replace previous prompt */
	} else {			/* ...else glue new stuff on old */
	    if (oldlen+lb->prmptsz > PROMPTBFSIZ-1) { /* if new stuf won't fit */
		len = (oldlen+lb->prmptsz)-(PROMPTBFSIZ-1);
		lb->prmptsz -= len;
		if (lb->prmptsz > 0) {	/* move everybody left n places */
		    for (dst = lb->prmpt; *dst = *(dst+len); ++dst);
		}
	    }
	}
	dst = lb->prmpt+lb->prmptsz;	/* point to place for prompt */
	while (*dst++ = *src++ );	/* copy in the string */
	lb->prmptsz = dst-lb->prmpt-1;	/* set the new length */
#if _SPTALLOC
	Sptfree(temp,oldlen+1);		/* done with temp space */
#endif
    }
}

/***************************************************************************
 * Breakthru. This routine is called when a message is to be sent to the
 * terminal while a read is in progress. The message is prefixed with a
 * \r<clear_to_eol> to make room on the current line for the new message
 * and all text up to and including the last \n is transmitted to the
 * terminal. Any text from the last \n to the end of the buffer is saved
 * in the broadcast clist which is transmitted either with the next 
 * message to be written or when the read completes. In any case, the
 * refresh bit is set to cause the user's command line to be reprinted
 * after the write completes.
 */
    	static int breakthru(tbp)
    	struct tty_buf *tbp;
/*
 * At entry:
 *	tbp - ptr to tty_buf
 *	u.u_base - ptr to message to send to terminal
 * At exit:
 *	user data is transmitted to the terminal
 */
{
    unsigned char last;
    int len;
    struct clist *bcl;
    bcl = &tbp->broadcast;		/* ptr to broadcast clist */
    copyin(u.u_base+u.u_count-1,&last,1);	/* pickup the last byte */
    if (last == '\n') {			/* if msg ends in a nl */
	if (bcl->c_cc > 0) {		/* first dump anything we have */
	    send_brdcst(tbp,1);		/* (preclearing the line) */
	} else {
	    cle_puts(tbp->ansi[ANSI_CLRLINE],tbp->ttyp);	/* start with a fresh line */
        }
	tbp->f_refresh = 1;		/* and cause a refresh */
    } else {				/* otherwise, save it for later */
        int len,oldlen;
        unsigned char *src,*dst;
#if _SPTALLOC
	unsigned char *temp;
#else
	unsigned char temp[PROMPTBFSIZ];
#endif
	len = 132;			/* assume max length */
	if (len > u.u_count) {		/* user data is smaller than 1 line */
	    if (bcl->c_cc+u.u_count > len) { /* but would overflow */
		send_brdcst(tbp,1);	/* send accumulated text */
		cle_puts("\r\n",tbp->ttyp); /* followed with a \r\n */
		tbp->f_refresh = 1;	/* reprint user's command */
	    }
	    len = u.u_count;		/* set length to user's */
	} else {			/* else userdata is longer */
	    if (bcl->c_cc > 0) {	/* so send anything we currently have */
	       send_brdcst(tbp,1);
            }
        }
	oldlen = len;
#if _SPTALLOC
	temp = (unsigned char *)Sptalloc(oldlen+1);	/* pick up some temp space */
#endif
	copyin(u.u_base+(u.u_count-len),temp,len);	/* get user's data */
	src = temp+len;			/* point to end */
	*src = 0;			/* null terminate it */
	for (;len > 0; --len) {		/* look for cr/lf */
            unsigned char c;
	    c = *--src;			/* from the back to the front */
	    if (c == CR || c == LF) {
		++src;			/* found one, it stays with... */
		break;			/* ...old message */
	    }
	}
	len = oldlen-len;		/* compute real length of message */
	if (bcl->c_cl != 0) {		/* if the clist is not empty */
	    int i;
   	    struct cblock *cbkp;
	    cbkp = bcl->c_cl;
	    i = CLSIZE-cbkp->c_last;	/* room in last cblock */
            if (i > 0) {
	        dst = &cbkp->c_data[cbkp->c_last];
	        if (i > len) i = len;	/* maximize it */
	        len -= i;		/* take from our count */
	        u.u_count -= i;		/* take from users' count */
	        bcl->c_cc += i;		/* bump size */
                cbkp->c_last += i;	/* move end ptr */
	        while (i-- > 0) *dst++ = *src++; /* put text at end of last cblock */
	    }
	}
	if (len > 0) {			/* if there's any text left */
	    int ospl;
	    struct clist tcl;
@//E*O*F cledab//
chmod u=rw,g=r,o=r cledab
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
   1500   7617  49699 cledab
!!!
wc  cledab | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0

-- 
Dave Shepperd.	    shepperd@dms.UUCP or motcsd!dms!shepperd
Atari Games Corporation, 675 Sycamore Drive, Milpitas CA 95035.
Nobody knows what I'm saying. I don't even know what I'm saying.

pjh@mccc.uucp (Pete Holsberg) (11/11/89)

Dave,
	3 and 4 made it here but 1 and 2 didn't.  If that's true for
other sites, could you repost them?  Thanks.
-- 
Pete Holsberg                UUCP: {...!rutgers!}princeton!mccc!pjh
Mercer College               CompuServe: 70240,334
1200 Old Trenton Road        GEnie: PJHOLSBERG
Trenton, NJ 08690            Voice: 1-609-586-4800

williams@cs.umass.edu (11/12/89)

In article <1989Nov11.031013.12665@mccc.uucp>, pjh@mccc.uucp (Pete Holsberg) writes...
> 
>Dave,
>	3 and 4 made it here but 1 and 2 didn't.  If that's true for
>other sites, could you repost them?  Thanks.
>-- 
>Pete Holsberg                UUCP: {...!rutgers!}princeton!mccc!pjh
>Mercer College               CompuServe: 70240,334
>1200 Old Trenton Road        GEnie: PJHOLSBERG
>Trenton, NJ 08690            Voice: 1-609-586-4800
We got them all.  Unless there are LOTS of people who said
they missed parts, please email them instead of reposting!