Line discipline part 4 of 4
Dave Shepperd
shepperd at dms.UUCP
Fri Nov 10 06:39:04 AEST 1989
# 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 at 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.
More information about the Comp.unix.i386
mailing list