home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-12-28 | 36.2 KB | 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 */
-