home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
1
/
1741
/
cled.c.2
Wrap
Text File
|
1990-12-28
|
37KB
|
1,786 lines
{
int ospl;
ospl = spl6();
{
last = next->last;
(tbp->last = last)->next = (tbp->next = next)->last = tbp;
}
splx(ospl);
}
#endif
tbp->flags = TB_INSERT;
setup_tcap_defaults(tbp);
setup_key_defaults(tbp);
tty_used = tbp;
return tbp;
}
/*
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.
ENTRY: Process context: task. Must not be called from interrupt. tp -
ptr to tty struct to match
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.
*/
static struct tty_buf *find_ttybuf(tp)
struct tty *tp;
{
register struct tty_buf *tbp;
int cnt = 0;
if (tty_used == 0)
return 0;
tbp = tty_used;
do
{
if (tbp->ttyp == tp)
{
#if INKERNEL
if (tbp != tty_used)
{
int ospl;
ospl = spl6();
{
register struct tty_buf *next,*last;
tbp->next->last = tbp->last;
tbp->last->next = tbp->next;
next = tty_used;
last = next->last;
(tbp->last = last)->next = (tbp->next = next)->last = tbp;
tty_used = tbp;
}
splx(ospl);
}
#endif /* INKERNEL */
return tbp;
}
tbp = tbp->next;
cnt++;
}
while (tbp != tty_used && cnt < cle_ttys);
return 0;
}
/*
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.
ENTRY: Process context: task. tbp - ptr to tty_buf which contains the
message clr_flg - true if the message line is to be precleared
EXIT: the cblock(s) holding the message are moved from the clist in
tty_buf to the t_outq clist.
*/
static void send_brdcst(tbp,clr_flg)
struct tty_buf *tbp;
int clr_flg;
{
#if INKERNEL
int ospl;
unchar c;
struct cblock *bp;
struct clist *bl,*tpc;
tpc = &tbp->ttyp->t_outq;
bl = &tbp->broadcast;
if (clr_flg)
{
cle_putc('\r',tbp->ttyp);
cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
}
ospl = spl6();
{
while ((bp = getcb(bl)) != 0)
putcb(bp,tpc);
kick_out(tbp->ttyp);
}
splx(ospl);
#endif /* INKERNEL */
}
/*
Open line discpline
ENTRY: tbp - ptr to tty_buf to open (or 0 if not preassigned) td - ptr
to tty struct to open
*/
static struct tty_buf *open_it(tbp,td)
register struct tty_buf *tbp;
struct tty *td;
{
int wasclosed;
#if INKERNEL
if (tbp != 0)
wasclosed = !(tbp->flags&TB_OPEN);
else
{
garbage_collect();
tbp = get_ttybuf(td);
wasclosed = YES;
}
if (tbp != 0)
{
tbp->flags |= (TB_OPEN|TB_OPENING);
if (wasclosed)
{
#if VERBOSE
show_pid(1," started by process ",td);
#endif
}
}
else
{
if (wasclosed)
{
cle_puts("\rNo buffers available to start cled\r\n",td);
u.u_error = ERR_NOTTYBUF;
}
}
if (wasclosed)
kick_out(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.
ENTRY: tp - ptr to tty struct process context: task.
EXIT: discipline 0 is opened.
*/
cleopen(tp)
struct tty *tp;
{
#if INKERNEL
(*linesw[0].l_open) (tp);
(void) open_it(find_ttybuf(tp),tp);
#endif
return 1;
}
/*
Close the line discpline
ENTRY: tbp - ptr to tty_buf to close (or 0 if not preassigned) td - ptr
to tty struct to open
*/
static void close_it(tbp,td)
struct tty_buf *tbp;
struct tty *td;
{
#if INKERNEL
if (tbp != 0)
{
int ospl;
if (td->t_state&ISOPEN)
{
#if VERBOSE
show_pid(0,"\rcled stopped by process ",td);
#endif
kick_out(td);
}
if (tbp->readsleep)
{
wakeup(tbp);
tbp->readsleep = NO;
if (td->t_state&ISOPEN)
tbp->flags |= TB_FLUSHIT;
}
ospl = spl6();
{
tbp->flags &=~ (TB_OPEN|TB_OPENING);
}
splx(ospl);
}
#if MULTILB
free_leds(tbp);
#endif
#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.
ENTRY: tp - ptr to tty struct process context: task.
EXIT: discipline 0 is closed.
*/
cleclose(tp)
struct tty *tp;
{
struct tty_buf *tbp;
tbp = find_ttybuf(tp);
#if INKERNEL
(*tp->t_proc) (tp,T_RESUME);
close_it(tbp,tp);
delay(HZ);
ttyflush(tp,FWRITE|FREAD);
(*linesw[0].l_close) (tp);
#endif
return 1;
}
#if INKERNEL
/*
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).
The input routine processes the characters in the device buffer, which
is an array, and then appends them to the raw queue, which is a clist.
It wakes up the waiting process, which will eventually call cleread that
will get the characters from the raw queue, to its internal history, and
then to the user.
If the line discipline is in raw mode, we check for VINTR and VQUIT and
send the appropriate signal. Notice that we cannot do this in cleread,
because cleread is only called when the user reads. We want to be able
to interrupt even if no read is outstanding.
*/
cleinput(td,bflg)
struct tty *td;
int bflg;
{
int i,indx,ospl;
unchar ch,*cp,*msg;
struct tty_buf *tbp;
i = 0;
tbp = tty_used;
if (tbp != 0)
do
{
if (tbp->ttyp == td)
break;
tbp = tbp->next;
++i;
}
while ((tbp != tty_used) && i < cle_ttys);
/*
If we cannot run, let ldisc 0 sort it out...
*/
if (CLEDOFF(td->t_lflag) || tbp == 0 || tbp->ttyp != td
|| (tbp->ttyp == td && (tbp->flags&TB_NOLINE)))
{
(*linesw[0].l_input) (td,bflg);
return;
}
/*
Our input is either a break condition or rbuf.
*/
if (bflg == L_BREAK)
{
if (!((td->t_lflag&ISIG) && (td->t_iflag&BRKINT)))
return;
cp = &ch;
ch = td->t_cc[VINTR];
i = 1;
}
else
{
if (td->t_rbuf.c_ptr == 0 || td->t_rbuf.c_count >= td->t_rbuf.c_size)
return;
i = td->t_rbuf.c_size - td->t_rbuf.c_count;
cp = (unchar *) td->t_rbuf.c_ptr;
td->t_rbuf.c_count = td->t_rbuf.c_size;
}
/*
Here we have cp that points at the array of chars to process,
and i is the number of such characters.
*/
for (i, cp; i > 0; --i, cp++)
{
register unchar c;
int quote;
c = *cp;
if (c == '\0')
continue;
/*
The switch character is very special. We cannot even
escape it.
*/
if (c == td->t_cc[VSWTCH])
{
if ((*td->t_proc) (td,T_SWTCH) != T_SWTCH)
return;
}
if (quote = (td->t_state & CLESC))
td->t_state &=~ CLESC;
if (!quote)
{
unchar quit,intr;
quit = td->t_cc[VQUIT];
intr = td->t_cc[VINTR];
if (c == quit || c == intr)
{
if (!(td->t_lflag&NOFLSH))
ttyflush(td,FWRITE|FREAD);
kick_out(td);
tbp->lbp->flags |= (c == intr) ? LD_INTR : LD_QUIT;
if (tbp->readsleep)
{
tbp->flags |= TB_FLUSHIT;
tbp->readsleep = NO;
wakeup(tbp);
}
signal(td->t_pgrp,(c == intr) ? SIGINT : SIGQUIT);
return;
}
else if (!CLEKEY_CHAR(c)
&& tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_PURGE)
{
ttyflush(td,FREAD);
if (tbp->readsleep)
{
tbp->flags |= TB_FLUSHIT;
break;
}
}
}
if (td->t_rawq.c_cc > (TTYHOG-3) || putc(c,&td->t_rawq) == -1)
{
tbp->flags |= TB_OVERUN;
cle_putc(BEL,td);
continue;
}
if (!quote)
{
if (!CLEKEY_CHAR(c) && tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_ESCAPE)
td->t_state |= CLESC;
else if
(
c == td->t_cc[VEOL]
|| c == td->t_cc[VEOL2]
|| c == td->t_cc[VEOF]
|| (!CLEKEY_CHAR(c)
&& tbp->keymap[CLEKEY_CMD(c)] == CLEFUN_NEWLINE))
{
/* count it so rdchk() works */
td->t_delct++;
}
}
}
if (tbp->readsleep)
{
tbp->readsleep = NO;
wakeup(tbp);
}
#if M_UNIX
/*
if by some chance, we're turned on while LD 0 is reading, wake it up
too
*/
if (td->t_state & IASLP)
#if M_ATT
ttrstrt(td);
#else
ttiwake(td);
#endif
#endif
}
/*
Output interrupt routine. This routine does nothing at this time. Control
is passed to discipline 0 for output. It normally just moves text from the
t_outq clist to the t_obuf output que. Null chars and timers may be set
appropriately depending on the char being output. This discipline has no
interest in changing the behaviour of the output routines.
ENTRY: td - ptr to tty struct Process context: Interrupt.
EXIT: Characters may have been moved from t_outq to t_obuf and the
output started.
*/
cleoutput(td)
struct tty *td;
{
return (*linesw[0].l_output) (td);
}
/*
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 situation.
ENTRY: arg - ptr to the tty_buf belonging to the process doing the read.
EXIT: TB_TIMEOUT set in the tty flags and a wakeup is delivered.
*/
static void read_timeout(arg)
struct tty_buf *arg;
{
if (arg->readsleep)
wakeup(arg);
arg->readsleep = NO;
}
/*
Announce that's there's no room at the inn
ENTRY: tp - ptr to tty struct typ - ascii string describing buffer type
that we're out of
EXIT: message output to the terminal line discipline reset to ld 0.
*/
static int no_room(tp,typ)
struct tty *tp;
unchar *typ;
{
cle_puts("\rInsufficient ",tp);
cle_puts(typ,tp);
cle_puts(" buffers to run cled at this time.\r",tp);
tp->t_line = 0;
(*linesw[0].l_read) (tp);
return 1;
}
#endif /* INKERNEL */
/*
Read a line from the terminal. This routine exits when the user types the
specified eol character (normally a \r).
ENTRY: Process context: task. tp - ptr to tty struct
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.
*/
cleread(tp)
struct tty *tp;
{
struct led_buf *lb;
struct tty_buf *tbp;
unchar *cp;
int c,len,time_id;
tbp = find_ttybuf(tp);
#if INKERNEL
if (tbp == 0)
return no_room(tp,"tty");
if (u.u_count == 0 || CLEDOFF(tp->t_lflag))
{
if (tbp != 0)
tbp->flags |= TB_NOLINE;
(*linesw[0].l_read) (tp);
return 1;
}
if (!(tbp->flags&TB_OPEN))
open_it(tbp,tp);
#endif
#if !MULTILB
lb = tbp->lbp;
#else
lb = find_ledbuf(tbp,u.u_procp);
if (lb == 0)
lb = get_ledbuf(tbp);
#endif
if (tbp->broadcast.c_cc != 0)
{
send_brdcst(tbp,0);
cle_putc('\n',tp);
tbp->dorefresh = YES;
}
#if INKERNEL
if (lb == 0)
{
close_it(tbp,tp);
return no_room(tp,"led");
}
#endif
tbp->flags &=~ (TB_NOLINE|TB_OPENING);
#if INKERNEL
if (lb->owed != 0)
{
len = lb->lcurs - lb->owed;
if (len > 0)
{
if (len > u.u_count)
len = u.u_count;
if (copyout(lb->owed,u.u_base,len) < 0)
{
u.u_error = EFAULT;
return 1;
}
lb->owed += len;
u.u_base += len;
u.u_count -= len;
if (lb->owed >= lb->lcurs)
lb->owed = 0;
return 1;
}
lb->owed = 0;
}
#endif
/*
Initialize command buffer and display to empty line
*/
lb->current = 0;
lb->lastchar = sizeof lb->line - 1;
lb->lcurs = lb->line;
lb->rcurs = lb->lineend = lb->line + lb->lastchar;
*lb->lcurs = *lb->rcurs = '\0';
lb->state = NORMAL;
/*
Reset history pointers to bottom
*/
lb->lastline = 0;
lb->matchlen = 0;
/*
Initialize flags
*/
lb->flags &=~ (LD_DONE|LD_EOF|LD_INTR|LD_QUIT|LD_INSERT);
lb->flags |= (LD_DIRTY);
if (tbp->flags&TB_INSERT)
lb->flags |= LD_INSERT;
tbp->flags |= TB_READING;
#if INKERNEL
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];
/*
Print any pending output
*/
while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
{
kick_out(tp);
delay(HZ/10);
}
#endif
while (!(lb->flags&LD_DONE))
{
#if INKERNEL
int ospl;
ospl = spl6();
{
/*
Wait for input if there is none queued
*/
if (tp->t_rawq.c_cc == 0)
{
if (tbp->dorefresh)
{
tbp->dorefresh = NO;
splx(ospl);
reprint(lb);
kick_out(tp);
continue;
}
if (!(tbp->flags&TB_OPEN))
{
lb->flags |= (LD_DONE|LD_EOF);
msg("Trying to cleread while CLED turned off",lb);
break;
}
if (tp->t_line != our_lineno || CLEDOFF(tp->t_lflag))
{
tp->t_line = our_lineno;
tp->t_iflag = tbp->iflag;
tp->t_oflag = tbp->oflag;
tp->t_lflag = tbp->lflag;
tp->t_cflag = tbp->cflag;
for (c = 0; c < NCC + 2; c++)
tp->t_cc[c] = tbp->cc[c];
tp->t_state |= ISOPEN;
tbp->dorefresh = YES;
msg("CLED: tty struct has been zapped. Resetting it.",lb);
continue;
}
/*
Sleep for a while for input to arrive
*/
time_id = timeout(read_timeout,tbp,HZ*15);
tbp->readsleep = YES;
if (sleep(tbp,(PZERO+8)|PCATCH))
{
ospl = spl6();
{
tbp->flags &=~ (TB_FLUSHIT|TB_READING);
tbp->dorefresh = tbp->readsleep = NO;
}
splx(ospl);
untimeout(time_id);
u.u_error = EINTR;
return -1;
}
/*
Alleluiah! We may have gotten something from cleinput
*/
untimeout(time_id);
splx(ospl);
while (tp->t_outq.c_cc != 0 || (tbp->flags&TB_WRITING))
{
kick_out(tp);
delay(HZ/10);
}
if (tbp->flags&TB_FLUSHIT)
{
bol(lb);
d_eol(lb);
ospl = spl6();
{
tbp->flags &=~ TB_FLUSHIT;
tbp->dorefresh = tbp->readsleep;
}
splx(ospl);
if (!(tbp->flags & TB_OPEN))
break;
}
continue;
}
}
splx(ospl);
#endif /* INKERNEL */
/*
Get next char from the raw input queue, filled by cleinput
*/
c = cle_getc(tp);
if (c != 0 && lb->state == NORMAL)
{
if (c == tp->t_cc[VERASE])
c = 0, lb->state = (NCC_SPC(VERASE));
else if (c == tp->t_cc[VKILL])
c = 0, lb->state = (NCC_SPC(VKILL));
else if (c == tp->t_cc[VEOL] || c == tp->t_cc[VEOL2])
c = 0, lb->state = (NCC_SPC(VEOL));
else if (c == tp->t_cc[VEOF])
c = 0, lb->state = (NCC_SPC(VEOL)), lb->flags = LD_EOF;
}
lb->c = c;
parse_it(lb);
#if INKERNEL
kick_out(tp);
#endif
}
tbp->flags &=~ TB_READING;
cp = lb->lcurs;
if (!(lb->flags&(LD_EOF/*|LD_INTR|LD_QUIT*/)))
{
*cp++ = '\n';
lb->lcurs = cp;
}
len = cp - lb->line;
#if INKERNEL
if (len != 0 && !(lb->flags&(LD_INTR|LD_QUIT)))
{
if (len > u.u_count)
len = u.u_count;
if (copyout(lb->line,u.u_base,len) < 0)
{
u.u_error = EFAULT;
return;
}
u.u_base += len;
u.u_count -= len;
tp->t_col = 0;
cle_putc('\r',tp); /* ICRNL */
cle_putc('\n',tp); /* OCRNL */
}
/* count down the delimiter */
if (tp->t_delct > 0)
--tp->t_delct;
if (tbp->broadcast.c_cc != 0)
{
send_brdcst(tbp,0);
cle_putc('\r',tp);
cle_putc('\n',tp);
}
kick_out(tp);
#else
strncpy(u.u_base,lb->line,len);
*(u.u_base + len) = 0;
#endif /* INKERNEL */
lb->owed = (lb->line + len >= lb->lcurs) ? (unchar *) 0 : lb->line+len;
lb->promptlen = 0;
lb->prompt[0] = '\0';
return 1;
}
#if INKERNEL
/*
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.
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)
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
MAXPROMPT parameter.
*/
static void catch_prompt(tbp,lb)
struct tty_buf *tbp;
struct led_buf *lb;
{
#if M_SPTALLOC
unchar *prompt;
#else
unchar prompt[MAXPROMPT+1];
#endif
int maxlen;
register unchar *tail,*old;
register int headlen;
if (tbp->broadcast.c_cc != 0)
send_brdcst(tbp,1);
/*
If the write is zero length, we just return; if the last
character of the write is a newline, than the write is surely
not for a prompt; prompts are non NL terminated writes.
*/
{
unchar ch;
if (copyin(u.u_base + u.u_count - 1,&ch,sizeof ch) < 0)
return;
if (ch == '\n')
{
lb->promptlen = 0;
lb->prompt[0] = '\0';
return;
}
}
#if M_SPTALLOC
prompt = (unchar *) Sptalloc(maxlen+1);
#endif
/*
Fetch the last maxlen characters of the prompt, and null
terminate them.
*/
maxlen = MIN(u.u_count,MAXPROMPT); /* This is at least 1 */
if (copyin(u.u_base + (u.u_count - maxlen),prompt,maxlen) < 0)
return;
*(tail = prompt + maxlen) = '\0';
/*
Determine the real prompt, which is the tail after the last
'\r' or '\n'. We *know* that maxlen != 0 implies tail > prompt initially.
*/
do --tail; while (tail > prompt && !(*tail == '\r' || *tail == '\n'));
if (*tail == '\r' || *tail == '\n') tail++;
/*
First we assume that the head of the new prompt is empty, then we
check; if the old prompt was not empty and the new prompt tail did not
start with '\r' or '\n', and leaves some space in the prompt buffer we
prepend the tail of the old prompt as the head of the new one,
shifting it into place if necessary. We expect this to be executed
very rarely; actually we should probably not bother at all...
*/
old = lb->prompt;
if (tail == prompt && lb->promptlen && !(tbp->flags&TB_WRITING)
&& (headlen = tail-prompt + MAXPROMPT-maxlen) > 0)
{
if (headlen >= lb->promptlen)
old += lb->promptlen;
else
{
bcopy(old+lb->promptlen-headlen,old,headlen);
old += headlen;
}
}
/*
A simple while will do instead of bcopy; we assume the tail will
usually be very small, i.e. <= 8 chars.
*/
while (*old++ = *tail++);
lb->promptlen = old-1 - lb->prompt;
#if M_SPTALLOC
Sptfree(temp,maxlen+1);
#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.
ENTRY: tbp - ptr to tty_buf u.u_base - ptr to message to send to
terminal.
EXIT: user data is transmitted to the terminal.
*/
#if BREAKTHRU
static void breakthru(tbp)
struct tty_buf *tbp;
{
unchar last;
int len;
struct clist *bcl;
if (copyin(u.u_base + u.u_count - 1,&last,1) < 0)
return;
bcl = &tbp->broadcast;
if (last == '\n')
{
if (bcl->c_cc > 0)
send_brdcst(tbp,YES);
else
{
cle_putc('\r',tbp->ttyp);
cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
}
tbp->dorefresh = YES;
}
else
{
int len,oldlen;
unchar *src,*dst;
#if M_SPTALLOC
unchar *temp;
#else
unchar temp[MAXPROMPT];
#endif
len = 132; /* assume max length */
if (len <= u.u_count)
{
if (bcl->c_cc > 0)
send_brdcst(tbp,1);
}
else
{
/* user data is smaller than 1 line */
/* but would overflow */
if (bcl->c_cc + u.u_count > len)
{
send_brdcst(tbp,1);
cle_putc('\r',tbp->ttyp);
cle_putc('\n',tbp->ttyp);
tbp->dorefresh = YES;
}
len = u.u_count;
}
oldlen = len;
#if M_SPTALLOC
temp = (unchar *) Sptalloc(oldlen + 1);
#endif
if (copyin(u.u_base + (u.u_count - len),temp,len) < 0)
return;
src = temp + len;
*src = '\0';
for (; len > 0; --len)
{
unchar c;
c = *--src;
if (c == '\r' || c == '\n')
{
++src;
break;
}
}
/* compute real length of message */
len = oldlen - len;
if (bcl->c_cl != 0)
{
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;
len -= i;
u.u_count -= i;
bcl->c_cc += i;
/* move end ptr */
cbkp->c_last += i;
while (i-- > 0)
*dst++ = *src++;
}
}
if (len > 0)
{
int ospl;
struct clist tcl;
/* init our dummy clist */
tcl.c_cc = 0;
tcl.c_cf = tcl.c_cl = 0;
u.u_count -= len;
ospl = spl6();
{
putcbp(&tcl,src,len);
}
splx(ospl);
/* if broadcast is empty */
if (bcl->c_cf == 0)
bcl->c_cf = tcl.c_cf;
else
bcl->c_cl->c_next = tcl.c_cf;
bcl->c_cc += tcl.c_cc;
bcl->c_cl = tcl.c_cl;
}
#if M_SPTALLOC
Sptfree(temp,oldlen + 1);
#endif
}
kick_out(tbp->ttyp);
}
#endif /* BREAKTHRU */
/*
Write some text to the terminal. Writes to the terminal can occur at any
time by any suitably privledged process. An attempt is made to determine
what writes constitute the output of a "prompt" string. This is done by
capturing and remembering in the brodcast clist a copy of the data to
write from the last \r or \n in the message to the end of the message.
Data that has no \r or \n in it is appended to any existing data in the
clist (often processes do single char output to the terminal so its no
wonder the system gets slow at times). If a led_buf has been assigned to
the process doing the write, then the "prompt" data is placed in the
led_buf instead of the broadcast clist. If a read is pending on the
terminal when a write is issued, only the data up to and including the
last \n is transmitted. The remainder is saved in the broadcast clist. If
data ends up being sent to the terminal, then the refresh bit is set and
the read process is awakened (which causes broadcast messages to
automatically refresh the input line).
ENTRY: Process context: task. td - ptr to tty struct
EXIT: Write data sent to the terminal and/or stored in the broadcast
clist or led_buf (if one assigned).
*/
clewrite(td)
struct tty *td;
{
int ospl;
struct led_buf *lb;
struct tty_buf *tbp;
if (CLEDOFF(td->t_lflag))
{
(*linesw[0].l_write)(td);
return;
}
tbp = find_ttybuf(td);
if (tbp != 0)
{
#if BREAKTHRU
if (tbp->flags&TB_READING)
breakthru(tbp);
else
#else
if (!(tbp->flags&TB_READING))
#endif
{
#if !MULTILB
lb = tbp->lbp;
if (u.u_count > 0)
catch_prompt(tbp,lb);
#else
lb = find_ledbuf(tbp,u.u_procp);
if (lb != 0)
{
if (u.u_count > 0)
catch_prompt(tbp,lb);
}
else
{
if (tbp->broadcast.c_cc > 0)
send_brdcst(tbp,0);
}
#endif
}
tbp->flags |= TB_WRITING;
}
if (u.u_count > 0)
(*linesw[0].l_write)(td);
else kick_out(td);
if (tbp != 0)
{
tbp->flags &=~ TB_WRITING;
ospl = spl6();
{
if (tbp->dorefresh && tbp->readsleep)
{
tbp->readsleep = NO;
wakeup(tbp);
}
}
splx(ospl);
}
}
#if VERBOSE
static void show_pid(disp,str,td)
int disp;
unchar *str;
struct tty *td;
{
unchar tmp[10],*s;
if (disp != 0)
{
cle_puts("\rcled version ",td);
cle_puts(VERSION,td);
cle_putc('.',td);
s = itoa(PATCHLEVEL,tmp,10); *s = '\0'; cle_puts(s,td);
cle_putc(' ',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;
}
#endif /* VERBOSE */
/*
Line discipline IOCTL routine.
ENTRY: Process context: task. td - ptr to tty struct f1 - function to
perform
EXIT: ioctl function is performed
*/
cleioctl(td,f1,arg,mode)
struct tty *td;
int f1,mode;
faddr_t arg;
{
struct tty_buf *tbp;
struct led_buf *lb;
tbp = find_ttybuf(td);
if (tbp != 0
&& ((tbp->flags&(TB_READING|TB_WRITING)) || !tbp->readsleep))
{
#if VERBOSE
cle_puts("CLED: ioctl issued while terminal busy. stty bits may be zapped",tbp->tbp);
#endif
kick_out(td);
}
if (f1 < LDGETCOLS)
{
if (f1 == LDCLOSE)
close_it(tbp,td);
else if (f1 == LDOPEN || f1 == LDCHG)
open_it(tbp,td);
(*linesw[0].l_ioctl) (td,f1,arg,mode);
kick_out(td);
return;
}
#if CLEDIO
garbage_collect(tbp);
if (tbp == 0)
tbp = get_ttybuf(td);
if (tbp == 0)
{
u.u_error = ERR_NOTTYBUF;
return;
}
#if MULTILB
if ((lb = tbp->lbp) != 0)
{
struct led_buf *us = 0,*parent = 0;
do
{
if (u.u_procp->p_ppid == lb->pid) parent = lb;
if (u.u_procp->p_pid == lb->pid) us = lb;
}
while ((lb = lb->next) != tbp->lbp);
lb = (us != 0) ? us : (parent != 0) ? parent : 0;
}
#else
lb = tbp->lbp;
#endif
switch (f1)
{
case LDGETCOLS:
if (copyout(&tbp->cols,arg,sizeof tbp->cols) < 0)
{
u.u_error = EFAULT;
return;
}
break;
case LDSETCOLS:
{
int cols;
if (copyin(arg,&cols,sizeof cols) < 0)
{
u.u_error = EFAULT;
return;
}
setcols(tbp,cols);
}
break;
case LDGETBF:
{
struct set_key sk;
char cnt,len;
faddr_t outp;
sk.modes = 0;
sk.modes |= (tbp->flags&TB_INSERT) ? CLEMODE_INSERT : CLEMODE_OVER;
sk.kdbuf_len = CLEKEY_MAX;
if (copyout(tbp->keymap,arg + sizeof (sk),CLEKEY_MAX) < 0)
{
u.u_error = EFAULT;
return;
}
outp = arg + sizeof (sk) + CLEKEY_MAX;
for (cnt = 0; cnt < TCAP_COUNT; ++cnt)
{
unchar *s;
if (copyout(&cnt,outp++,1) < 0)
{
u.u_error = EFAULT;
return;
}
s = (unchar *) tbp->tcap[cnt];
while (*s++);
len = s - (unchar *) tbp->tcap[cnt];
if (copyout(tbp->tcap[cnt],outp,len) < 0)
{
u.u_error = EFAULT;
return;
}
outp += len;
}
sk.tcapbuf_len = outp - (arg + sizeof (sk) + CLEKEY_MAX);
if (copyout(&sk,arg,sizeof (sk)) < 0)
{
u.u_error = EFAULT;
return;
}
}
break;
case LDSETBF:
{
struct set_key sk;
int oldflag;
if (copyin(arg,&sk,sizeof (sk)) < 0)
{
u.u_error = EFAULT;
return;
}
oldflag = tbp->flags;
if (sk.modes & CLEMODE_INSERT) tbp->flags |= TB_INSERT;
else if (sk.modes & CLEMODE_OVER) tbp->flags &= ~TB_INSERT;
if (sk.kdbuf_len > CLEKEY_MAX)
{
sk.kdbuf_len = CLEKEY_MAX;
if (copyout(&sk,arg,sizeof (sk)) < 0)
{
u.u_error = EFAULT;
return;
}
u.u_error = ERR_BADPARAM;
return;
}
if (sk.kdbuf_len > 0)
{
#if M_SPTALLOC
unchar *tmp,*kp;
#else
unchar tmp[100],*kp;
#endif
int cnt,size;
size = sk.kdbuf_len * 2;
#if M_SPTALLOC
kp = tmp = (unchar *) Sptalloc(size);
#else
if (size > sizeof (tmp))
{
u.u_error = ERR_BADPARAM;
return;
}
kp = tmp;
#endif
if (copyin(arg + sizeof (sk),tmp,size) < 0)
{
u.u_error = EFAULT;
return;
}
for (cnt = 0; cnt < sk.kdbuf_len; ++cnt)
{
int key,func;
key = *kp++;
func = *kp++;
if (key >= CLEKEY_MAX || func >= CLEFUN_MAX)
{
#if M_SPTALLOC
Sptfree(tmp,size);
#endif
sk.kdbuf_len = cnt;
copyout(&sk,arg,sizeof (sk));
u.u_error = ERR_BADPARAM;
return;
}
tbp->keymap[CLEKEY_CMD(key)] = func;
}
#if M_SPTALLOC
Sptfree(tmp,size);
#endif
}
if (sk.tcapbuf_len > 0)
{
setup_tcap_defaults(tbp);
if (sk.tcapbuf_len > 1)
{
unchar *s;
int nfg = 0;
#if M_SPTALLOC
s = tbp->tcstrings = (unchar *) Sptalloc(sk.tcapbuf_len);
#else
s = tbp->tcstrings;
if (sk.tcapbuf_len > TCAP_SIZE)
{
sk.tcapbuf_len = TCAP_SIZE;
copyout(&sk,arg,sizeof (sk));
u.u_error = ERR_BADPARAM;
return;
}
#endif
tbp->tclen = sk.tcapbuf_len;
if (copyin(arg + sizeof (sk) + sk.kdbuf_len*2,s,tbp->tclen) < 0)
{
u.u_error = EFAULT;
return;
}
while (s < tbp->tcstrings + tbp->tclen)
{
unchar *ap;
int str;
str = *s++;
if (str >= TCAP_COUNT)
{
nfg = 1;
break;
}
ap = s;
while (*ap && ap < tbp->tcstrings + tbp->tclen)
++ap;
if (*ap != 0)
{
nfg = 1;
break;
}
tbp->tcap[str] = (char *) s;
s = ap + 1;
}
if (nfg)
{
sk.tcapbuf_len = s - tbp->tcstrings;
copyout(&sk,arg,sizeof (sk));
u.u_error = ERR_BADPARAM;
return;
}
}
}
}
break;
case LDGETHB:
if (lb == 0)
{
u.u_error = ERR_NOLBASS;
return;
}
if (copyout(lb->history,arg,MAXHISTORY) < 0)
{
u.u_error = EFAULT;
return;
}
break;
default:
u.u_error = ERR_BADIOCTL;
}
#endif /* CLEDIO */
}
/*
Device driver entry points; used for backdoor setup of CLED.
*/
cledinit(dev)
int dev;
{
int cnt;
for (cnt = 0; cnt < linecnt; ++cnt)
if (linesw[cnt].l_open == cleopen)
break;
if (cnt < linecnt)
{
our_lineno = cnt;
printf("CLED %s PL%d is ldisc %d.\n",VERSION,PATCHLEVEL,cnt);
garbage_collect((struct tty_buf *) 0);
}
else
{
#if M_UNIX
cmn_err(CE_WARN,"CLED %s not in linesw table. Not installed",VERSION);
#else
printf("CLED %s not in linesw table. Not installed.\n",VERSION);
#endif
}
return;
}
cledioctl(dev,cmd,arg,mode)
int dev,cmd,mode;
faddr_t arg;
{
switch (cmd)
{
#if CLEDIO
case LDGETS:
{
int cnt;
unchar *s;
struct led_buf *lb;
struct tty_buf *tbp;
struct cle_stats sts;
sts.line = our_lineno;
sts.ledbufs = cle_leds;
sts.ttybufs = cle_ttys;
sts.promptsize = MAXPROMPT;
sts.linesize = MAXLINE;
sts.histsize = MAXHISTORY;
sts.multi_lb = MULTILB;
sts.spt = M_SPTALLOC;
#if M_SPTALLOC
sts.tcapsize = 256;
#else
sts.tcapsize = TCAP_SIZE;
#endif
s = (unchar *) VERSION;
for (cnt = 0; cnt < 4; ++cnt)
{
if ((sts.vers[cnt] = *s++) == 0)
break;
}
tbp = tty_free;
cnt = 0;
if (tbp != 0)
{
do
{
tbp = tbp->next;
++cnt;
} while (tbp != tty_free && cnt < cle_ttys);
}
sts.ttybufs_used = cle_ttys - cnt;
#if !MULTILB
sts.ledbufs_used = sts.ttybufs_used;
#else
cnt = 0;
lb = ldb_free;
if (lb != 0)
{
do
{
lb = lb->next;
++cnt;
}
while (lb != ldb_free && cnt < cle_leds);
}
sts.ledbufs_used = cle_leds - cnt;
#endif
if (copyout(&sts,arg,sizeof (struct cle_stats)) < 0)
{
u.u_error = EFAULT;
return;
}
}
break;
#endif /* CLEDIO */
#if DEBUG
case LDGETB:
{
struct cle_buf bfs;
bfs.lbsize = cle_leds * sizeof (struct led_buf);
bfs.tbsize = cle_ttys * sizeof (struct tty_buf);
bfs.lbbase = cle_buffers;
#if MULTILB
bfs.lbfree = ldb_free;
#else
bfs.lbfree = 0;
#endif
bfs.tbbase = cle_ttybuf;
bfs.tbused = tty_used;
bfs.tbfree = tty_free;
bfs.procbase = proc;
if (copyout(&bfs,arg,sizeof (struct cle_buf)) < 0)
{
u.u_error = EFAULT;
return;
}
arg += sizeof (struct cle_buf);
if (copyout(cle_buffers,arg,bfs.lbsize) < 0)
{
u.u_error = EFAULT;
return;
}
arg += bfs.lbsize;
if (copyout(cle_ttybuf,arg,bfs.tbsize) < 0)
{
u.u_error = EFAULT;
return;
}
}
break;
case LDGETTTY:
{
struct tty *ttyp;
if (copyin(arg,&ttyp,sizeof (ttyp)) < 0
|| copyout(ttyp,arg,sizeof (struct tty)) < 0)
{
u.u_error = EFAULT;
return;
}
}
break;
case LDGETC:
{
struct clist *clp;
struct cblock *cbp;
int cnt;
if (copyin(arg,&clp,sizeof (clp)) < 0)
{
u.u_error = EFAULT;
return;
}
if (clp->c_cc != 0)
{
int ospl;
ospl = spl6();
{
cbp = clp->c_cf;
do
{
unchar siz;
siz = cbp->c_last - cbp->c_first;
if (siz != 0)
{
if (copyout(&siz,arg,1) < 0)
{
u.u_error = EFAULT;
return;
}
++arg;
if (copyout(&cbp->c_data[cbp->c_first],arg,siz) < 0)
{
u.u_error = EFAULT;
return;
}
arg += siz;
}
cbp = cbp->c_next;
} while (cbp != 0);
}
splx(ospl);
}
cnt = 0;
if (copyout(&cnt,arg,1) < 0)
{
u.u_error = EFAULT;
return;
}
}
break;
#endif /* M_DEBUG */
default:
u.u_error = ERR_BADIOCTL;
}
}
#else /* INKERNEL */
static unchar cmd_line[256];
static struct tty dum_tty;
struct termio ostate; /* saved tty state */
struct termio nstate; /* values for editor mode */
main()
{
int c;
dum_tty.t_cc[VINTR] = 'C' & 0x1f;
dum_tty.t_cc[VQUIT] = '\\' & 0x1f;
dum_tty.t_cc[VERASE] = RUB;
dum_tty.t_cc[VKILL] = 'U' & 0x1f;
dum_tty.t_cc[VEOF] = 'D' & 0x1f;
dum_tty.t_cc[VEOL] = 'M' & 0x1f;
ioctl(0,TCGETA,&ostate);
ioctl(0,TCGETA,&nstate);
nstate.c_iflag = 0;
nstate.c_oflag = 0;
nstate.c_lflag = 0;
nstate.c_cc[VEOF] = 1;
nstate.c_cc[VEOL] = 0;
ioctl(0,TCSETA,&nstate);
u.u_base = cmd_line;
u.u_count = sizeof (cmd_line);
garbage_collect((struct tty_buf *) 0);
tty_used = cle_ttybuf;
get_ttybuf(&dum_tty);
cle_puts("Outputting controls\r\n",&dum_tty);
while (cleread(&dum_tty) && strlen(cmd_line))
fprintf(stderr,"\r\nRead %d chars\r\n",strlen(cmd_line));
ioctl(0,TCSETA,&ostate);
return;
}
#endif /* INKERNEL */