CLED 2.5 SystemV/386 part 03/03
Piercarlo Grandi
pcg at cs.aber.ac.uk
Wed Aug 29 02:34:59 AEST 1990
--------------------------cut here--------------------------------------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 3 (of 3)."
# Contents: cled.c.1
# Wrapped by sw at aware on Tue Aug 28 13:36:12 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cled.c.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cled.c.1'\"
else
echo shar: Extracting \"'cled.c.1'\" \(44477 characters\)
sed "s/^X//" >'cled.c.1' <<'END_OF_FILE'
X/*
X $Id: cled.c,v 2.5 90/08/26 11:32:08 sw Exp $
X
X A simple line editor intended for command line editing on Xenix
X with a TCAP type terminal using the line discipline mode of
X terminal operation.
X
X Authors:
X
X Piercarlo Grandi (piercarl). Aberystwyth. (pcg at cs.aber.ac.uk):
X
X substantially cleaned up the code and made it more modular
X and readable. More configurable, with an EMACS key bindings
X options for non DEC VT compatible terminals. Able to work
X on dumb terminals if necessary. Corrected a few bugs.
X
X Dave Shepperd (dms). Atari Games, corp. (shepperd at dms.UUCP):
X
X hacked lvr's editor to bits to make it re-entrant and added
X the line discipline and device interfaces for SCO Xenix/386.
X
X Lyle Rains (lvr). Atari Games, corp. (rains at dms.UUCP):
X
X wrote the editor in 1983 or so for a RT-11 system intended to be
X included as a library module.
X
X Copyright 1989,1990 Piercarlo Grandi (parts).
X Copyright 1989 Atari Games, Corp. (most).
X
X Reproduction, adaptation, distribution, performance or display of
X this computer program or the associated documentation is not
X prohibited provided this copyright notice accompanies said
X reproduction, adaptation, distribution, performance or display.
X*/
X
X#include <sys/types.h>
X#include <sys/tty.h>
X#include <sys/termio.h>
X
X#include "patchlevel.h"
X#include "sys/cledio.h"
X#include "sys/cled.h"
X
X#include <sys/param.h>
X#include <sys/sysmacros.h>
X#include <sys/conf.h>
X#include <sys/errno.h>
X
X#ifdef M_KERNEL
X# undef INKERNEL
X# define INKERNEL 1
X#endif
X
X#ifdef INKERNEL
X# undef M_KERNEL
X# define M_KERNEL 1
X#endif
X
X#if INKERNEL
X# if M_UNIX
X# include <sys/immu.h>
X# include <sys/region.h>
X# else
X# include <sys/mmu.h>
X# endif
X# if M_I386
X# include <sys/page.h>
X# include <sys/seg.h>
X# endif
X# include <sys/proc.h>
X# include <sys/var.h>
X# include <sys/dir.h>
X# include <sys/signal.h>
X# include <sys/user.h>
X# if M_UNIX && defined(ftop)
X# undef ftop
X# endif
X# include <sys/ioctl.h>
X# include <sys/file.h>
X# if M_UNIX
X# include <sys/cmn_err.h>
X# endif
X#endif
X
Xextern int cle_ttys;
Xextern int cle_leds;
X
Xextern struct led_buf cle_buffers[];
Xextern struct tty_buf cle_ttybuf[];
X
X/*
X Control characters
X*/
X
X#define BEL 007
X#define ESC 033
X#define RUB 0177
X
X/*
X Parser states
X*/
X
X#define NORMAL 0x0000
X#define ESCAPE 0x0001
X#define ANSIKEY 0x0002
X#define QUOTE 0x0003
X#define NCC_SPC(c) (0x0100+(c))
X
X/*
X Boolean type and values
X*/
X
X#define FLAG unchar
X
X#define YES 1
X#define NO 0
X#define DEL 1
X#define NODEL 0
X
X#if INKERNEL
X# define cle_putc(c,tp) putc((c),&(tp)->t_outq)
X# define cle_getc(tp) getc(&(tp)->t_rawq)
X#else
X# include <stdio.h>
X# include <malloc.h>
X# define cle_puts(str,tp) if (str) fputs((str),stderr)
X# define cle_putc(chr,tp) fputc((chr),stderr)
X# define cle_getc(tp) fgetc(stdin)
X#endif
X
X#define MIN(a,b) ((a) < (b) ? (a) : (b))
X#define history_end(lb) ((lb)->historyend-1)
X
Xstatic unchar our_lineno;
X
X/*
X This routine is a dummy routine that simply marks the start of cled in
X the map file (for trouble shooting)
X*/
X
Xvoid cled_begin(){}
X
X/*
X The following n routines comprise the editor proper. The process
X context in all cases is task time. None of these routines are (nor
X should they ever be) called at interrupt time.
X*/
X
Xstatic void pfront();
Xstatic void pback();
Xstatic void bol();
Xstatic void eol();
X
Xstatic void reprint();
Xstatic void ring_bell();
Xstatic void kick_out();
X
Xstatic unchar echo();
X
X/*
X Put a string of text into the command buffer, echoing them as they are
X inserted.
X
X ENTRY: cp - ptr to string of chars to be copied cnt - count of chars to
X copy lb - ptr to led_buf into which to place the text
X
X EXIT: chars moved into lb->line[lb->lcurs]. lb->lcurs adjusted as
X required lb->rcurs adjusted if overstrike mode lb->flags may be set
X chars echoed as required
X*/
X
Xstatic void putt(cp,cnt,lb)
X register unchar *cp;
X int cnt;
X struct led_buf *lb;
X{
X register unchar **rc,**lc;
X int gap;
X int last;
X unsigned iflg;
X struct tty *typ;
X
X rc = &lb->rcurs;
X lc = &lb->lcurs;
X
X typ = lb->tbp->ttyp;
X iflg = typ->t_iflag;
X
X /*
X We want the line not to grow beyond cols, including the prompt and
X an empty position at the end of the line to avoid problems with
X automargin terminals.
X */
X
X last = lb->tbp->cols - lb->promptlen - 1;
X gap = (MAXLINE-lb->tbp->cols + 1) + lb->promptlen + 1;
X
X while (cnt--)
X {
X register unchar ch = *cp;
X
X if (iflg&ISTRIP) ch &= 0x7F;
X
X if (ch != '\0')
X {
X if ((iflg&IUCLC) && ch >= 'A' && ch <= 'Z')
X ch += 'a' - 'A';
X
X if ((*rc - *lc) <= gap || (ch = echo(ch,lb,last)) == '\0')
X break;
X
X *(*lc)++ = *cp++ = ch;
X if (!(lb->flags&LD_INSERT) && *(*rc) != '\0')
X (*rc)++;
X
X lb->flags |= LD_DIRTY;
X }
X }
X
X *(*lc) = '\0';
X
X if (cnt >= 0)
X ring_bell(lb);
X
X pback(lb,NO);
X}
X
X/*
X Find pointer to n'th string in a history or key define buffer.
X
X ENTRY: start - ptr into buffer where search is to begin ndx - the
X number of the string to find
X
X EXIT: returns ptr to first char of requested string if present else it
X returns ptr to null string at end of buffer.
X*/
X
Xstatic unchar *ptr(start,ndx)
X register unchar *start;
X register int ndx;
X{
X while (ndx-- && *start)
X start += *start;
X
X return start;
X}
X
X/*
X Find the pointer to matching string in a history or key define buffer.
X
X ENTRY: src - ptr to place in buffer to begin the search. patt - ptr
X to string to match against len - len of string pointed to by patt indx
X - ptr to int into which the number of the found string in the buffer
X is placed. exact - if YES, the lengths must match as well as the
X pattern. if NO, only 'len' chars are compared.
X
X EXIT: returns ptr to first char in found string or ptr to null string
X at end of buffer if no match. *indx is updated if the string is found
X otherwise it is not changed.
X*/
X
Xstatic unchar *match_ptr(src,patt,len,indx,exact)
X unchar *src,*patt;
X int exact,len,*indx;
X{
X int nxtndx;
X
X for
X (
X nxtndx = *indx, src = ptr(src,nxtndx);
X *src != '\0';
X nxtndx++, src += *src
X )
X if ((*src - 1) == len || (exact == NO && (*src - 1) > len))
X {
X int result;
X register int tlen;
X register unchar *a,*b;
X
X result = 0;
X
X for (a = src+1, b = patt, tlen = len; tlen != 0; --tlen)
X if ((result = *a++ - *b++) != 0)
X break;
X
X if (result == 0)
X break;
X }
X
X if (*src == '\0')
X src = (unchar *) '\0';
X else *indx = nxtndx;
X
X return src;
X}
X
X/*
X Place n'th string from history or key definition buffer into command buff
X
X ENTRY: src - ptr to place in history or key def buffer to begin search
X ndx - number of string to pick up lb - ptr to led_buf into which to
X place the found string
X
X EXIT: requested string (or null string) is moved to command buf
X replacing whatever might be there already. A number of members of the
X lb struct will have been changed.
X*/
X
Xstatic void getstr(src,ndx,lb)
X register unchar *src;
X int ndx;
X struct led_buf *lb;
X{
X register unsigned cnt;
X
X src = ptr(src,ndx);
X if (cnt = (unsigned) *src++)
X putt(src,--cnt,lb);
X}
X
X/*
X Move the cursor n places to the left.
X
X ENTRY: cnt - number of column positions to move left delete - if 1,
X delete the characters under the cursor as it is moved if 0, don't
X delete the chars under the cursor lb - ptr to led_buf which holds the
X cursor info
X
X EXIT: cursor is moved left appropriately unless it is already at the
X left margin in which case nothing will happen. Characters may be
X echoed or the right half of the line may be redrawn if deleting. A
X number of members of the lb struct will have been changed.
X*/
X
Xstatic void curs_l(cnt,delete,lb)
X int cnt;
X FLAG delete;
X struct led_buf *lb;
X{
X register unchar *rc,*lc;
X register FLAG atab;
X register struct tty *typ;
X
X atab = NO;
X
X rc = lb->rcurs;
X lc = lb->lcurs;
X typ = lb->tbp->ttyp;
X
X while ((lc > lb->line) && cnt--)
X {
X if ((*--rc = *--lc) == '\t')
X atab |= YES;
X
X lb->current--;
X if (!atab)
X cle_putc('\b',typ);
X }
X *(lb->lcurs = lc) = '\0';
X
X if (atab)
X pfront(lb,NO);
X
X if (delete)
X {
X lb->flags |= LD_DIRTY;
X pback(lb,YES);
X }
X else
X {
X lb->rcurs = rc;
X if (atab)
X pback(lb,NO);
X }
X}
X
X/*
X Move the cursor n places to the right.
X
X ENTRY: cnt - number of column positions to move right delete - if 1,
X delete the characters under the cursor as it is moved if 0, don't
X delete the chars under the cursor lb - ptr to led_buf which holds the
X cursor info
X
X EXIT: cursor is moved right appropriately unless it is already at the
X right margin in which case nothing will happen. Characters may be
X echoed or the right half of the line may be redrawn if deleting. A
X number of members of the lb struct will have been changed.
X*/
X
Xstatic void curs_r(cnt,delete,lb)
X int cnt;
X FLAG delete;
X struct led_buf *lb;
X{
X register unchar *rc,*lc;
X
X rc = lb->rcurs;
X lc = lb->lcurs;
X
X if (!delete)
X {
X while (*rc && cnt--) *lc++ = echo(*rc++,lb,MAXLINE);
X lb->rcurs = rc;
X *(lb->lcurs = lc) = '\0';
X }
X else
X {
X while (*rc && cnt--) rc++;
X lb->rcurs = rc;
X lb->flags |= LD_DIRTY;
X pback(lb,YES);
X }
X}
X
X/*
X Test a char for being alpha-numeric.
X
X ENTRY: chr - chr to test
X
X EXIT: returns YES if chr is alpha-numeric or '_'
X*/
X
Xstatic int isaln(chr)
X register unchar chr;
X{
X return (
X (chr >= 'a' && chr <= 'z')
X || (chr >= 'A' && chr <= 'Z')
X || (chr >= '0' && chr <= '9')
X || chr == '_'
X );
X}
X
X/*
X Test a char for being white-space.
X
X ENTRY: chr - chr to test
X
X EXIT: returns YES if chr is white-space
X*/
X
Xstatic int isws(chr)
X register unchar chr;
X
X{
X return (chr == ' ' || chr == '\t' || chr == '\n');
X}
X
X/*
X Test a char for being delimiter.
X
X ENTRY: chr - chr to test
X
X EXIT: returns YES if chr is delimiter
X*/
X
Xstatic int isdelim(chr)
X register unchar chr;
X{
X return (!isaln(chr) && !isws(chr));
X}
X
X/*
X Skip to end of "word" on the left and optionally 'eat' it.
X
X ENTRY: lb - ptr to led_buf
X
X EXIT: cursor moved. "word" skipped
X*/
X
Xstatic void skipwl(lb)
X struct led_buf *lb;
X{
X register unchar *cp;
X
X cp = lb->lcurs;
X
X while (cp > lb->line && isws(*(cp-1))) --cp;
X while (cp > lb->line && isaln(*(cp-1))) --cp;
X while (cp > lb->line && isdelim(*(cp-1))) --cp;
X
X curs_l(lb->lcurs - cp,NO,lb);
X}
X
X/*
X Skip to end of "word" on the right and optionally 'eat' it.
X
X ENTRY: lb - ptr to led_buf
X
X EXIT: cursor moved. "word" either skipped or eaten
X*/
X
Xstatic void skipwr(lb)
X struct led_buf *lb;
X{
X register unchar *cp;
X
X cp = lb->rcurs;
X
X while (*cp && isdelim(*cp)) ++cp;
X while (*cp && isaln(*cp)) ++cp;
X while (*cp && isws(*cp)) ++cp;
X
X curs_r(cp - lb->rcurs,NO,lb);
X}
X
X/*
X Delete 'word' to left of cursor
X
X ENTRY: lb - ptr to led_buf containing cmd_buf
X
X EXIT: 'word' to left of cursor is deleted unless cursor is already at
X left margin in which case nothing happens. Several members of the lb
X struct are updated.
X*/
X
Xstatic void d_lwrd(lb)
X struct led_buf *lb;
X{
X register unchar *cp;
X
X cp = lb->lcurs;
X
X while (cp > lb->line && isws(*(cp - 1))) --cp;
X curs_l(lb->lcurs - cp,NO,lb);
X
X while (cp > lb->line && isaln(*(cp - 1))) --cp;
X while (cp > lb->line && isdelim(*(cp - 1))) --cp;
X curs_l(lb->lcurs - cp,YES,lb);
X}
X
X/*
X Delete 'word' to right of cursor
X
X ENTRY: lb - ptr to led_buf containing cmd_buf
X
X EXIT: 'word' to right of cursor is deleted unless cursor is already at
X right margin in which case nothing happens. Several members of the lb
X struct are updated.
X*/
X
Xstatic void d_rwrd(lb)
X struct led_buf *lb;
X{
X register unchar *cp;
X
X cp = lb->rcurs;
X
X while (*cp && isws(*cp)) ++cp;
X curs_r(cp - lb->rcurs,NO,lb);
X
X while (*cp && isdelim(*cp)) ++cp;
X while (*cp && isaln(*cp)) ++cp;
X curs_r(cp - lb->rcurs,YES,lb);
X}
X
X/*
X Copy current contents of command buf to key def buffer
X
X ENTRY: cp - ptr to place in key def buffer to deposit cmd buf len -
X number of chars to move lb - ptr to led_buf containing the cmd buf At
X exit: command string is moved to requested spot in buffer Strings in
X the history buffer may be deleted if there's overlap. A number of
X members of the lb struct will have been changed.
X*/
X
Xstatic void copycom(cp,len,lb)
X register unchar *cp;
X register len;
X struct led_buf *lb;
X{
X register unchar *cp2;
X
X if (len > (TTYHOG-3))
X return;
X
X cp2 = lb->line;
X *cp++ = len;
X while (--len)
X *cp++ = *cp2++;
X
X /* eliminate oldlines if overwritten */
X for (cp = lb->history; *cp && (cp + *cp) <= history_end(lb); cp += *cp);
X
X *cp = '\0';
X}
X
X/*
X Complete the read (insert a newline in command buffer)
X
X ENTRY: lb - ptr to led_buf containing cmd_buf
X
X EXIT: lb struct is cleaned up and a LD_DONE is set in flags to
X indicate the read is complete. The contents of the command line is
X inserted in the history buffer. If it matches a line already in the
X history buffer, the dup is removed and the new one is inserted at the
X front. Several members of the lb struct are updated.
X*/
X
Xstatic void newline(lb)
X struct led_buf *lb;
X{
X register unchar *end;
X register unchar *cp;
X int linelen;
X
X eol(lb);
X linelen = (lb->lcurs - lb->line) + 1;
X
X if (linelen > 1 && linelen < ((history_end(lb) - lb->history) - 1))
X {
X /*
X If dirty = NO, then we used an old line without modification so
X we'll squeeze it out of the old buffer to eliminate the
X repetition, and recopy it into the front of the old buffer. This
X allows us to hold older commands longer. If dirty = YES, then
X we'll look for a matching command in the buffer and, if one is
X found, move it to the head of the buffer. If not, then we just
X insert the new string at the head of the buffer.
X */
X
X if (!(lb->flags&LD_DIRTY))
X end = ptr(lb->history,lb->lastline);
X else
X {
X lb->lastline = 0;
X end = match_ptr(lb->history,lb->line,linelen - 1,&lb->lastline,YES);
X if (end == 0)
X end = lb->historyend - linelen;
X lb->matchlen = linelen;
X }
X
X for (cp = end + linelen; end > (lb->history + 1); *--cp = *--end);
X copycom(lb->history + 1,linelen,lb);
X }
X
X lb->flags |= LD_DONE;
X}
X
X#if INKERNEL
X
X/*
X Kick start the output. This routine is called whenever there is data in
X the t_outq buffer to make sure that it gets sent to the terminal.
X
X ENTRY: Process context: Task or Interrupt. May be called from either.
X tp - ptr to tty struct
X
X EXIT: If data present in t_outq and output not already running, then a
X call to the terminal driver processor routine (t_proc) with the output
X option selected is made which will cause data to be moved from the
X t_outq clist to the t_obuf output array for subsequent output to the
X hardware.
X*/
X
Xstatic void kick_out(tp)
X struct tty *tp;
X{
X int ospl;
X
X ospl = spl6();
X {
X if (tp->t_outq.c_cc != 0
X && (!(tp->t_state & (BUSY|TIMEOUT|TTSTOP))
X || tp->t_tbuf.c_count == 0))
X {
X splx(ospl);
X (*tp->t_proc) (tp,T_OUTPUT);
X }
X }
X splx(ospl);
X}
X
X/*
X Put a null terminated string of characters in the output que for
X subsequent output to the terminal.
X
X ENTRY: Process context: Task or Interrupt. s - ptr to null terminated
X string to output tp - ptr to tty struct
X
X EXIT: characters are placed in the t_outq clist. If there's no room
X for the whole message, that that won't fit is discarded with no error.
X*/
X
Xstatic void cle_puts(s,tp)
X unchar *s;
X struct tty *tp;
X{
X register unchar *s1 = s;
X struct clist dumcl,*clp;
X struct cblock *srcp;
X int ospl,cnt;
X
X if (s1 == 0 || *s1 == 0)
X return;
X
X while (*s1++);
X cnt = s1-1 - s;
X
X dumcl.c_cc = 0;
X dumcl.c_cf = dumcl.c_cl = 0;
X clp = &tp->t_outq;
X
X ospl = spl6();
X {
X putcbp(&dumcl,s,cnt);
X while ((srcp = getcb(&dumcl)) != 0)
X putcb(srcp,clp);
X }
X splx(ospl);
X}
X#endif
X
X/*
X Echo a char to the terminal
X
X ENTRY: chr - char to be echoed lb - ptr to led_buf containing cmd_buf.
X
X EXIT: chr is written to the output que (t_outq) and may be enclosed
X with inverse video escape sequences if the char is non-printable. Tabs
X are expaned to an appropriate number of spaces. Several members in the
X lb struct will have been changed.
X*/
X
Xstatic unchar echo(chr,lb,last)
X register unchar chr;
X register struct led_buf *lb;
X int last;
X{
X struct tty_buf *tbp;
X struct tty *typ;
X
X tbp = lb->tbp;
X typ = tbp->ttyp;
X
X if (lb->current >= last)
X return 0;
X
X if (CLEKEY_CHAR(chr))
X lb->current += 1,cle_putc(chr,typ);
X else if (chr == '\t')
X {
X chr = 8 - ((lb->current+lb->promptlen) & 7);
X if ((lb->current += chr) >= last)
X {
X lb->current -= chr;
X return '\0';
X }
X
X /*
X Here we must use spaces and not tabs because we may
X want to overwrite.
X */
X while (chr--) cle_putc(' ',typ);
X
X chr = '\t';
X }
X else
X {
X unchar **tcap = (unchar **) tbp->tcap;
X
X lb->current += 1;
X
X if (chr == RUB) chr = '?' - '@';
X cle_puts(tcap[TCAP_SETINV],typ);
X cle_putc(chr + '@',typ);
X cle_puts(tcap[TCAP_SETNORM],typ);
X }
X
X return chr;
X}
X
X/*
X Print the prompt string to the terminal
X
X ENTRY: lb - ptr to led_buf containing prompt string clr_flg - YES if to
X pre-clear the line before printing
X
X EXIT: prompt string is written to the output que (t_outq). Some chars
X may be converted to displayable ones.
X*/
X
Xstatic void pprompt(lb,clr_flg)
X register struct led_buf *lb;
X int clr_flg;
X{
X register unchar *cp;
X register struct tty_buf *tbp = lb->tbp;
X
X cle_putc('\r',tbp->ttyp);
X
X#if 0
X if (lb->promptlen) cle_puts(lb->prompt,tbp->ttyp);
X#else
X for (cp = lb->prompt; *cp && echo(*cp++,lb,tbp->cols-1););
X#endif
X
X if (clr_flg)
X cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X}
X
X/*
X Print the text to the left of the cursor
X
X ENTRY: lb - ptr to led_buf containing prompt string clr_flg - YES if to
X pre-clear the line before printing
X
X EXIT: The prompt string and the text from lb->line[0] through
X lb->line[lb->lcurs] is put in the output que (t_outq). Some characters
X may have bee converted to displayable ones. The message completes with
X an escape sequence to turn on the cursor.
X*/
X
Xstatic void pfront(lb,clr_flg)
X register struct led_buf *lb;
X int clr_flg;
X{
X register unchar *cp;
X
X lb->current = 0;
X pprompt(lb,clr_flg);
X for (cp = lb->line; *cp && echo(*cp++,lb,MAXLINE););
X}
X
X/*
X Print the text from the cursor to the end of line
X
X ENTRY: lb - ptr to led_buf containing prompt string deol - if 1, follows
X message with an escape sequence to delete to end of line. if 0, don't
X delete to end of line
X
X EXIT: String from lb->line[lb->rcurs] to end of buffer is sent to the
X output que (t_outq).
X*/
X
Xstatic void pback(lb,deol)
X struct led_buf *lb;
X int deol;
X{
X register unchar *cp;
X register int tmp1,tmp2;
X unchar **tcap;
X struct tty *typ;
X struct tty_buf *tbp;
X int save;
X
X tbp = lb->tbp;
X typ = tbp->ttyp;
X tcap = (unchar **) tbp->tcap;
X
X if (*lb->rcurs == 0)
X {
X if (deol)
X cle_puts(tcap[TCAP_CLREOL],typ);
X return;
X }
X
X save = tcap[TCAP_SAVE] && *tcap[TCAP_SAVE];
X
X if (save)
X cle_puts(tcap[TCAP_SAVE],typ);
X
X tmp1 = lb->current;
X for (cp = lb->rcurs; *cp && echo(*cp,lb,MAXLINE); cp++);
X tmp2 = lb->lastchar;
X lb->lastchar = lb->current;
X lb->current = tmp1;
X
X if (save)
X {
X if (deol)
X cle_puts(tcap[TCAP_CLREOL],typ);
X cle_puts(tcap[TCAP_RESTORE],typ);
X }
X else
X {
X for (tmp1 = tmp2 - lb->lastchar; tmp1--; cle_putc(' ',typ));
X for (tmp1 = tmp2 - lb->current; tmp1--; cle_putc('\b',typ));
X }
X}
X
X/*
X Send a message to the terminal
X
X ENTRY: str - pointer to null terminated string containing message lb -
X ptr to led_buf to which to send the message
X
X EXIT: message is placed in output que (t_outq) wrapped with the
X necessary escape sequences to make the message appear on the line
X above the current line. Command line is refreshed.
X*/
X
Xstatic void msg(str,lb)
X unchar *str;
X struct led_buf *lb;
X{
X long oldq;
X register struct tty_buf *tbp;
X register struct tty *typ;
X
X tbp = lb->tbp;
X typ = tbp->ttyp;
X oldq = lb->flags;
X
X cle_putc('\r',typ);
X cle_puts(tbp->tcap[TCAP_CLREOL],typ);
X cle_puts(tbp->tcap[TCAP_SETINV],typ);
X cle_puts(str,typ);
X cle_puts(tbp->tcap[TCAP_SETNORM],typ);
X cle_putc('\n',typ);
X reprint(lb);
X}
X
X/*
X right arrow, move cursor non-destructively
X*/
Xstatic void c_r(lb)
X struct led_buf *lb;
X{
X curs_r(1,NODEL,lb);
X}
X
X/*
X left arrow, move cursor non-destructively
X*/
Xstatic void c_l(lb)
X struct led_buf *lb;
X{
X curs_l(1,NODEL,lb);
X}
X
Xstatic void d_eol(lb)
X struct led_buf *lb;
X{
X register struct tty_buf *tbp = lb->tbp;
X
X lb->rcurs = lb->lineend;
X *lb->rcurs = '\0';
X cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X}
X
Xstatic void d_bol(lb)
X struct led_buf *lb;
X{
X curs_l(MAXLINE,DEL,lb);
X}
X
Xstatic void d_rchr(lb)
X struct led_buf *lb;
X{
X curs_r(1,DEL,lb);
X}
X
Xstatic void d_lchr(lb)
X struct led_buf *lb;
X{
X curs_l(1,DEL,lb);
X}
X
Xstatic void eol(lb)
X struct led_buf *lb;
X{
X curs_r(MAXLINE,NODEL,lb);
X}
X
Xstatic void bol(lb)
X struct led_buf *lb;
X{
X curs_l(MAXLINE,NODEL,lb);
X}
X
Xstatic void tog_insrt(lb)
X struct led_buf *lb;
X{
X lb->flags ^= LD_INSERT;
X}
X
Xstatic void reprint(lb)
X struct led_buf *lb;
X{
X pfront(lb,NO);
X pback(lb,YES);
X}
X
Xstatic void getold_prev(lb)
X register struct led_buf *lb;
X{
X register int *xptr;
X register struct tty_buf *tbp = lb->tbp;
X
X xptr = &lb->lastline;
X pprompt(lb,NO);
X
X lb->lcurs = lb->line;
X lb->rcurs = lb->lineend;
X lb->current = 0;
X
X /* recall this way eats pattern */
X lb->matchlen = 0;
X
X if (*ptr(lb->history,*xptr))
X getstr(lb->history,++(*xptr),lb);
X cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X
X lb->flags &=~ (LD_DIRTY);
X}
X
Xstatic void getold_next(lb)
X register struct led_buf *lb;
X{
X register int *xptr;
X register struct tty_buf *tbp = lb->tbp;
X
X xptr = &lb->lastline;
X pprompt(lb,NO);
X
X lb->lcurs = lb->line;
X lb->rcurs = lb->lineend;
X lb->current = 0;
X
X /* recall this way eats pattern */
X lb->matchlen = 0;
X if (*xptr)
X getstr(lb->history,--(*xptr),lb);
X cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X
X lb->flags &=~ (LD_DIRTY);
X}
X
Xstatic void getold_str(lb)
X register struct led_buf *lb;
X{
X register int linelen;
X unchar *new;
X register struct tty_buf *tbp = lb->tbp;
X
X eol(lb);
X
X linelen = (lb->lcurs - lb->line);
X if (linelen == 0)
X return;
X
X if ((lb->flags&LD_DIRTY) || lb->matchlen == 0)
X {
X lb->matchlen = linelen;
X lb->lastline = 0;
X }
X else
X {
X if (*ptr(lb->history,lb->lastline))
X lb->lastline++;
X else
X {
X ring_bell(lb);
X return;
X }
X }
X
X new = match_ptr(lb->history,lb->line,lb->matchlen,&lb->lastline,NO);
X
X if (new == 0)
X {
X ring_bell(lb);
X return;
X }
X
X pprompt(lb,NO);
X
X lb->lcurs = lb->line;
X lb->rcurs = lb->lineend;
X lb->current = 0;
X
X if (linelen = *new++)
X putt(new,--linelen,lb);
X cle_puts(tbp->tcap[TCAP_CLREOL],tbp->ttyp);
X
X lb->flags &=~ (LD_DIRTY);
X}
X
Xstatic void meta(lb)
X struct led_buf *lb;
X{
X lb->state = ESCAPE;
X}
X
Xstatic void ansi(lb)
X struct led_buf *lb;
X{
X lb->state = ANSIKEY;
X}
X
X/*
X Hardwired ANSI key map for the IBM PC.
X*/
X
Xstatic int ansikey(ch)
X register char ch;
X{
X switch (ch)
X {
X case '@': return CLEFUN_INSERT;
X case 'A': return CLEFUN_PREVIOUS;
X case 'B': return CLEFUN_NEXT;
X case 'C': return CLEFUN_CURSR;
X case 'D': return CLEFUN_CURSL;
X case 'H': return CLEFUN_GOTOBOL;
X case 'U': return CLEFUN_SKIPWR;
X case 'V': return CLEFUN_SKIPWL;
X case 'Y': return CLEFUN_GOTOEOL;
X default: return CLEFUN_BELL;
X }
X}
X
Xstatic void superquote(lb)
X struct led_buf *lb;
X{
X putt("^",1,lb); c_l(lb);
X lb->state = QUOTE;
X}
X
Xstatic void self_insert(lb)
X struct led_buf *lb;
X{
X putt(&lb->c,1,lb);
X}
X
Xstatic void nop(lb)
X struct led_buf *lb;
X{
X}
X
Xstatic void ring_bell(lb)
X struct led_buf *lb;
X{
X register struct tty_buf *tbp = lb->tbp;
X
X cle_puts(tbp->tcap[TCAP_FLASH],tbp->ttyp);
X}
X
X/* DON'T CHANGE THE ORDER OF THE ENTRIES IN THE FOLLOWING 3 ARRAYS */
X
Xstatic void (*edit_functions[]) () =
X{
X self_insert, /* insert a char */
X tog_insrt, /* toggle insert/overstrike mode */
X bol, /* goto bol */
X eol, /* goto eol */
X d_lwrd, /* delete "word" to the left */
X d_rwrd, /* delete "word" to the right */
X d_bol, /* delete to beginning of line */
X d_eol, /* delete to end of line */
X c_l, /* cursor left */
X c_r, /* cursor right */
X d_lchr, /* delete character on left */
X d_rchr, /* delete character on right */
X reprint, /* refresh the line */
X getold_prev, /* get previous */
X getold_next, /* get next */
X getold_str, /* get matching string */
X newline, /* end of input */
X superquote, /* escape next char */
X nop, /* do nothing */
X ring_bell, /* echo a bell */
X skipwl, /* skip word right */
X skipwr, /* skip word left */
X nop, /* actually purge (trapped at interrupt time) */
X meta, /* meta/ESC key */
X ansi, /* ANSI cursors, ESC [ */
X 0 /* trailer */
X};
X
Xstatic unchar hex[] = "0123456789ABCDEF";
X
Xstatic unchar *itoa(val,ptr,radix)
X register unsigned int val;
X unchar *ptr;
X register int radix;
X{
X unsigned quo;
X register unsigned rem;
X
X rem = val % radix;
X quo = val / radix;
X if (quo != 0)
X ptr = itoa(quo,ptr,radix);
X *ptr++ = hex[rem];
X return ptr;
X}
X
X/*
X parse_it is the entry point for the editor. It is called for each
X character input from the keyboard. The process context is task time. It
X must never be called from an interrupt routine.
X
X ENTRY: lb - ptr to led_buf for this process. lb->c has character to
X process.
X
X EXIT: the command line is edited.
X*/
X
Xstatic void parse_it(lb)
X register struct led_buf *lb;
X{
X int s = lb->state;
X register unchar c = lb->c;
X register unchar *kmap = lb->tbp->keymap;
X
X lb->state = NORMAL; /* next default state ... */
X
X switch (s)
X {
X case NORMAL:
X if (CLEKEY_CHAR(c))
X putt(&lb->c,1,lb);
X else (*edit_functions[kmap[CLEKEY_CMD(c)]]) (lb);
X break;
X
X case ESCAPE:
X if (CLEKEY_CHAR(c))
X (*edit_functions[kmap[c]]) (lb);
X else ring_bell(lb);
X break;
X
X case ANSIKEY:
X (*edit_functions[ansikey(c)]) (lb);
X break;
X
X case QUOTE:
X d_rchr(lb);
X if (c != '\0')
X putt(&lb->c,1,lb);
X else msg("NULs cannot be inserted",lb);
X break;
X
X default:
X
X switch (s)
X {
X case NCC_SPC(VEOL): newline(lb); break;
X case NCC_SPC(VERASE): d_lchr(lb); break;
X case NCC_SPC(VKILL): d_bol(lb); break;
X
X default:
X msg("Unknown key and/or key state",lb);
X }
X }
X}
X
X/*
X The following n routines are specific to the line discipline and are what
X are called by the kernel. Process context can be both task time and
X interrupt time and is so indicated at the entry point of each routine.
X
X The pre-processor variable INKERNEL is defined when compiling for line
X discipline mode. If it is not defined, then the program will be made in
X standalone mode which is useful for debugging the edit only portion of the
X program.
X*/
X
X/*
X allocate a dummy u struct if s.a. mode
X*/
X#if !INKERNEL
Xstruct user
X{
X unchar *u_base;
X int u_count;
X int u_error;
X struct proc *u_procp;
X} u;
X#endif
X
X#if MULTILB
Xstatic struct led_buf *ldb_free;
X#endif
X
Xstatic struct tty_buf *tty_free;
Xstatic struct tty_buf *tty_used;
X
X#if DEBUG
Xstatic VOID dump_ttybuf(tbp,msg)
X struct tty_buf *tbp;
X unchar *msg;
X{
X register struct tty_buf *nxt;
X
X if (tbp == 0)
X {
X printf("%s: tbp = 0\n",msg);
X return;
X }
X
X nxt = tbp;
X
X do
X {
X printf("%s: tbp = %X, next = %X, last = %X, tp = %X\n\tlbp = %X, flags = %X\n",
X msg,nxt,nxt->next,nxt->last,nxt->ttyp,nxt->lbp,nxt->flags);
X nxt = nxt->next;
X }
X while (nxt != tbp);
X
X}
X
Xstatic void dump_ledbuf(lb,msg)
X struct led_buf *lb;
X unchar *msg;
X{
X struct led_buf *nlb;
X
X if (lb == 0)
X {
X printf("%s: lb = 0\n",msg);
X return;
X }
X
X nlb = lb;
X do
X {
X printf("%s: lb = %X, next = %X, last = %X, td = %X\n\tttybf = %X, flags = %X\n",
X msg,nlb,nlb->next,nlb->last,nlb->tbp->ttyp,nlb->tbp,nlb->flags);
X nlb = nlb->next;
X }
X while (nlb != lb);
X}
X
X#if MULTILB
Xstatic void dump_buftree(tbp)
X struct tty_buf *tbp;
X{
X struct led_buf *lb;
X struct tty_buf *utbp;
X
X printf("Into dump_buftree(): tbp = %X\n",tbp);
X dump_ttybuf(tty_used,"Used");
X dump_ttybuf(tty_free,"Free");
X
X if (tbp != 0)
X {
X printf("lbp = %X\n",tbp->lbp);
X dump_ledbuf(tbp->lbp,"Used");
X }
X
X dump_ledbuf(ldb_free,"Free");
X printf("Strike any key to continue: ");
X (void) getchar();
X printf("Out of dump_buftree()\n");
X}
X#endif
X
Xstatic void dump_clist(clp,msg)
X struct clist *clp;
X unchar *msg;
X{
X struct cblock *cbp;
X int size;
X
X printf("dump_clist() [%s]: ptr = %x\n",msg,clp);
X
X if (clp == 0 || clp->c_cf == 0)
X {
X printf("clist is empty\n");
X return;
X }
X
X printf("\tcc = %d, first = %x, last = %x\n",clp->c_cc,clp->c_cf,clp->c_cl);
X cbp = clp->c_cf;
X
X size = 0;
X do
X {
X unchar tstr[clsize + 1],*dst,*src;
X int i;
X
X dst = tstr;
X src = &cbp->c_data[(i = cbp->c_first)];
X for (; i < cbp->c_last; ++i)
X {
X unchar c;
X
X c = *src++;
X if (!CLEKEY_CHAR(c))
X c = '.';
X *dst++ = c;
X }
X *dst = '\0';
X
X printf("\t%x, next = %x, first = %d, last = %d, size = %d\n",
X cbp,cbp->c_next,cbp->c_first,cbp->c_last,cbp->c_last - cbp->c_first);
X printf("\tstr = {%s}\n",tstr);
X
X size += cbp->c_last - cbp->c_first;
X if (cbp == clp->c_cl)
X break;
X
X cbp = cbp->c_next;
X }
X while (cbp != 0);
X
X if (size != clp->c_cc)
X printf("\taccumulated size of %d doesn't match c_cc size of %d\n",
X size,clp->c_cc);
X
X printf("type any char to continue");
X (void) getchar();
X putchar('\n');
X}
X#endif /* DEBUG */
X
X/*
X set the keymap to defaults.
X*/
X
Xstatic void setup_key_defaults(tbp)
X struct tty_buf *tbp;
X{
X register int cnt;
X register unchar *kmap;
X
X for (kmap = tbp->keymap, cnt = 0; cnt < CLEKEY_MAX; ++cnt)
X *kmap++ = CLEFUN_BELL;
X
X kmap = tbp->keymap;
X
X kmap['\0'] = CLEFUN_NOP;
X kmap[CLEKEY_CTL('A')] = CLEFUN_GOTOBOL;
X kmap[CLEKEY_CTL('B')] = CLEFUN_CURSL;
X kmap[CLEKEY_CTL('D')] = CLEFUN_DELCRIT;
X kmap[CLEKEY_CTL('E')] = CLEFUN_GOTOEOL;
X kmap[CLEKEY_CTL('F')] = CLEFUN_CURSR;
X kmap[CLEKEY_CTL('G')] = CLEFUN_BELL;
X kmap[CLEKEY_CTL('H')] = CLEFUN_DELCRIT;
X kmap[CLEKEY_CTL('I')] = CLEFUN_CHAR;
X kmap['\n'] = CLEFUN_NEWLINE;
X kmap[CLEKEY_CTL('K')] = CLEFUN_DELEOL;
X kmap[CLEKEY_CTL('L')] = CLEFUN_REFRESH;
X kmap['\r'] = CLEFUN_NEWLINE;
X kmap[CLEKEY_CTL('N')] = CLEFUN_NEXT;
X kmap[CLEKEY_CTL('P')] = CLEFUN_PREVIOUS;
X kmap[CLEKEY_CTL('Q')] = CLEFUN_ESCAPE;
X kmap[CLEKEY_CTL('R')] = CLEFUN_FIND;
X kmap[CLEKEY_CTL('U')] = CLEFUN_DELBOL;
X kmap[CLEKEY_CTL('V')] = CLEFUN_ESCAPE;
X kmap[CLEKEY_CTL('W')] = CLEFUN_DELWLFT;
X kmap[CLEKEY_CTL('Y')] = CLEFUN_PURGE;
X kmap[CLEKEY_CTL('^')] = CLEFUN_ESCAPE;
X kmap[ESC] = CLEFUN_META;
X kmap[CLEKEY_CTL('\\')] = CLEFUN_FIND;
X kmap[RUB] = CLEFUN_DELCLFT;
X
X kmap[CLEKEY_ESC('d')] = CLEFUN_DELWRIT;
X kmap[CLEKEY_ESC('f')] = CLEFUN_SKIPWR;
X kmap[CLEKEY_ESC('b')] = CLEFUN_SKIPWL;
X kmap[CLEKEY_ESC('p')] = CLEFUN_FIND;
X kmap[CLEKEY_ESC('[')] = CLEFUN_ANSI;
X kmap[CLEKEY_ESC('-')] = CLEFUN_DELWLFT;
X}
X
X/*
X The following init's setup the strings required to make a terminal do the
X given functions.
X*/
X
Xstatic void setup_tcap_defaults(tbp)
X struct tty_buf *tbp;
X{
X tbp->tcap[TCAP_CLREOL] = TCAP_CLREOL_STR;
X tbp->tcap[TCAP_SETINV] = TCAP_SETINV_STR;
X tbp->tcap[TCAP_SETNORM] = TCAP_SETNORM_STR;
X tbp->tcap[TCAP_SAVE] = TCAP_SAVE_STR;
X tbp->tcap[TCAP_RESTORE] = TCAP_RESTORE_STR;
X tbp->tcap[TCAP_FLASH] = TCAP_FLASH_STR;
X
X#if M_SPTALLOC
X if (tbp->tcstrings != 0)
X {
X sptfree(tbp->tcstrings,tbp->tclen,1);
X tbp->tcstrings = 0;
X tbp->tclen = 0;
X }
X#else
X tbp->tclen = 0;
X#endif
X}
X
X/*
X Initialize the tty and led free lists. Threads the entries in the
X tty buf array together and on the tty_free list, and either
X assigns each led buf to a tty buf or threads the led buf array in
X a free list, depending on whether MULTILB is true.
X*/
X
Xstatic void freelist_init()
X{
X register int cnt;
X
X#if MULTILB
X {
X register struct led_buf *lastlb;
X
X /*
X Thread first led buf
X */
X lastlb = &cle_buffers[0];
X lastlb->next = lastlb->last = lastlb;
X
X /*
X Append the rest, if any, to the last
X */
X for (lastlb, cnt = 1; cnt < cle_ttys; cnt++,lastlb++)
X {
X register struct led_buf *lb = lastlb+1;
X
X lb->next = lastlb->next;
X lb->last = lastlb;
X lb->next->last = lastlb->next = lb;
X }
X
X ldb_free = cle_buffers;
X }
X#endif
X
X {
X register struct tty_buf *lasttbp;
X
X /*
X Thread first tty buf
X */
X lasttbp = cle_ttybuf;
X lasttbp->next = lasttbp->last = lasttbp;
X lasttbp->lbp = 0;
X
X /*
X Append rest, if any, to the end
X */
X for (lasttbp, cnt = 1; cnt < cle_ttys; cnt++, lasttbp++)
X {
X register struct tty_buf *tbp = lasttbp+1;
X
X tbp->lbp = 0;
X tbp->next = lasttbp->next;
X tbp->last = lasttbp;
X tbp->next->last = lasttbp->next = tbp;
X }
X }
X
X#if !MULTILB
X {
X register struct led_buf *lb = &cle_buffers[0];
X register struct tty_buf *tbp = &cle_ttybuf[0];
X
X for (lb, tbp, cnt = 0; cnt < cle_ttys; cnt++, lb++, tbp++)
X {
X lb->tbp = tbp;
X tbp->lbp = lb;
X }
X }
X#endif
X
X tty_free = cle_ttybuf;
X}
X
Xstatic void zap_lb(lb,flags)
X register struct led_buf *lb;
X int flags;
X{
X lb->flags = (flags&TB_INSERT) ? LD_INSERT : 0;
X
X /*
X Last byte is a fake key definition buffer, length 1 byte, empty.
X */
X
X *lb->history = 1;
X *(lb->history+1) = '\0';
X
X lb->historyend = lb->history+MAXHISTORY - 1;
X *lb->historyend = '\0';
X
X lb->owed = 0;
X
X lb->promptlen = 0;
X}
X
X#if INKERNEL
X
X#if MULTILB
X/*
X Put the led buf beloning to the given tty buf back on the free list.
X*/
X
Xstatic struct led_buf *free_lb(lb,tbp)
X register struct led_buf *lb;
X register struct tty_buf *tbp;
X{
X struct led_buf *nxtlb;
X
X /*
X Detach from the list of led bufs for this tty buf
X */
X
X if (lb == lb->next)
X nxtlb = tbp->lbp = 0;
X else
X {
X nxtlb = lb->next;
X lb->next->last = lb->last;
X lb->last->next = lb->next;
X if (lb == tbp->lbp)
X tbp->lbp = lb->next;
X }
X
X /*
X Clean things up
X */
X
X lb->proc = 0;
X lb->flags = 0;
X lb->tbp = 0;
X
X /*
X Attach to free list
X */
X
X if (ldb_free == 0)
X lb->next = lb->last = lb;
X else
X {
X lb->last = ldb_free->last;
X lb->next = ldb_free;
X lb->last->next = ldb_free->last = lb;
X }
X
X ldb_free = lb;
X
X return nxtlb;
X}
X
X/*
X For a given tty buffer, scan the chain of led bufs and free any that
X are attached to defunct processes.
X*/
X
Xstatic void free_leds(tbp)
X register struct tty_buf *tbp;
X{
X register struct led_buf *lb;
X
X lb = tbp->lbp;
X
X do
X {
X lb =
X (
X lb->tbp == 0
X || lb->proc == 0
X || lb->proc->p_pid != lb->pid
X || lb->proc->p_ppid != lb->ppid
X )
X ? free_lb(lb,tbp) : lb->next;
X }
X while (lb != tbp->lbp);
X}
X#endif /* MULTILB */
X
Xstatic struct tty_buf *free_ttybuf(tbp)
X register struct tty_buf *tbp;
X{
X struct tty_buf *nxttbp;
X
X /*
X Detach it from the tty_used list
X */
X
X if (tbp == tbp->next)
X nxttbp = tty_used = 0;
X else
X {
X int ospl;
X
X ospl = spl6();
X {
X tbp->next->last = tbp->last;
X tbp->last->next = tbp->next;
X if (tbp == tty_used)
X tty_used = tbp->next;
X nxttbp = tbp->next;
X }
X splx(ospl);
X }
X
X /*
X Disgorge any pending output, and clean things up
X */
X
X if (tbp->broadcast.c_cf != 0)
X {
X struct cblock *cnxt;
X int ospl;
X
X ospl = spl6();
X {
X while ((cnxt = getcb(&tbp->broadcast)) != 0)
X putcf(cnxt);
X kick_out(tbp->ttyp);
X }
X splx(ospl);
X }
X
X tbp->flags = 0;
X tbp->dorefresh = tbp->readsleep = NO;
X
X /*
X Attach to the free list
X */
X
X if (tty_free == 0)
X tbp->next = tbp->last = tbp;
X else
X {
X register struct tty_buf *tn;
X
X tn = tty_free->next;
X (tbp->next = tn)->last = (tbp->last = tty_free)->next = tbp;
X }
X
X tty_free = tbp;
X
X return nxttbp;
X}
X
X/*
X For each tty buf, free up all the led bufs not attached to
X any process, and free all those (except for the one passed
X as an argument) that have no led bufs left and are not
X open.
X*/
X
Xstatic void free_ttys(oldtbp)
X struct tty_buf *oldtbp;
X{
X register struct tty_buf *tbp;
X
X tbp = tty_used;
X
X do
X {
X register struct tty_buf *nxttbp = tbp->next;
X
X#if MULTILB
X if (tbp->lbp != 0)
X free_leds(tbp);
X#endif
X
X tbp =
X (
X tbp != oldtbp
X && tbp->readsleep == NO
X#if MULTILB
X && !(tbp->flags&TB_OPENING)
X && tbp->lbp == 0
X#else
X && !(tbp->flags&TB_OPEN)
X#endif
X )
X ? free_ttybuf(tbp) : tbp->next;
X }
X while (tbp != tty_used);
X}
X#endif /* INKERNEL */
X
X/*
X Ran out of tty_buf's or led_buf's so ripple through the allocated ones and
X deallocate any that are no longer being used. It is also called to init
X the links in the structures.
X
X ENTRY: Process context: task. NEVER call from an interrupt routine.
X oldtbp: ptr to tbp buffer of buffer not to put on free list; tty_free:
X points to first element in free list for tty_buf's; tty_used: points to
X first element in used list for tty_buf's; ldb_free: points to first element
X in free list for led_buf's
X
X EXIT: all led_buff's assigned to defunct processes are placed back in
X the free list. All tty_buf's that have no led_buf's assigned are
X placed back in the free list.
X*/
X
Xstatic void garbage_collect(oldtbp)
X struct tty_buf *oldtbp;
X{
X if (tty_used == 0 && tty_free == 0)
X freelist_init();
X#if INKERNEL
X else if (tty_used != 0)
X free_ttys(oldtbp);
X#endif
X}
X
X/*
X Get the next available led_buf from the freelist.
X
X ENTRY: Process context: task. Must never be called from
X interrupt routine. tbp - ptr to tty_buf assigned to tty
X struct to which led_buf is to be attached.
X
X EXIT: returns ptr to led_buf if one is available else returns 0. If
X led_buf is attached, it is placed at the head of the que; tbp->lbp
X will be moved in that case. The led_buf is initialised for use. The
X history buffer is purged.
X*/
X
Xstatic struct led_buf *get_ledbuf(tbp)
X struct tty_buf *tbp;
X{
X struct led_buf *lb,*next,*last;
X int cnt;
X unchar *chr;
X
X#if !MULTILB
X lb = tbp->lbp;
X#else
X if (ldb_free == 0)
X {
X garbage_collect(tbp);
X if (ldb_free == 0)
X return 0;
X }
X
X /*
X Detach first led buf in free chain
X */
X
X lb = ldb_free;
X
X if (lb->next == lb)
X ldb_free = 0;
X else
X {
X lb->next->last = lb->last;
X lb->last->next = lb->next;
X ldb_free = lb->next;
X }
X
X /*
X Attach as first led buf in the tty buf' chain.
X */
X
X if (tbp->lbp == 0)
X lb->next = lb->last = lb;
X else
X {
X next = tbp->lbp;
X last = next->last;
X (lb->last = last)->next = (lb->next = next)->last = lb;
X }
X
X#if INKERNEL
X lb->proc = u.u_procp;
X lb->pid = u.u_procp->p_pid;
X lb->ppid = u.u_procp->p_ppid;
X#endif
X
X lb->tbp = tbp;
X tbp->lbp = lb;
X#endif /* MULTILB */
X
X zap_lb(lb,tbp->flags);
X
X return lb;
X}
X
X#if MULTILB
X/*
X Find the led_buf in the list belonging to this process.
X
X ENTRY: Process context: task. Must never be called from interrupt
X routine. tbp - ptr to tty_buf assigned to tty struct which has led_buf que
X uproc - pointer to element in process table (used only to inspect the
X p_pid and p_ppid fields).
X
X EXIT: returns ptr to led_buf if one is found else returns 0. If
X led_buf is found, it is placed at the head of the que; tbp->lbp may
X be moved in that case.
X*/
X
Xstatic struct led_buf *find_ledbuf(tbp,uproc)
X struct tty_buf *tbp;
X struct proc *uproc;
X{
X register struct led_buf *lb;
X int cnt = 0;
X
X if (tbp->lbp == 0)
X return 0;
X
X lb = tbp->lbp;
X
X do
X {
X#if INKERNEL
X if ((lb->proc != 0 && lb->proc == uproc)
X && (lb->pid == uproc->p_pid && lb->ppid == uproc->p_ppid))
X {
X if (lb != tbp->lbp)
X {
X struct led_buf *next,*last;
X
X lb->last->next = lb->next;
X lb->next->last = lb->last;
X next = tbp->lbp;
X last = next->last;
X (lb->last = last)->next = (lb->next = next)->last = lb;
X tbp->lbp = lb;
X }
X
X return lb;
X }
X#endif /* INKERNEL */
X
X lb = lb->next;
X cnt++;
X }
X while (lb != tbp->lbp && cnt < cle_leds);
X
X return 0;
X}
X
X#endif /* MULTILB */
X
Xstatic void setcols(tbp,cols)
X register struct tty_buf *tbp;
X int cols;
X{
X if (cols < 8)
X {
X u.u_error = ERR_BADPARAM;
X return;
X }
X
X if (cols >= MAXLINE)
X cols = MAXLINE;
X
X tbp->cols = cols;
X}
X
X/*
X Get a tty_buf from the free pool.
X*/
X
X/*
X ENTRY: Process context: task. Never call this from an interrupt
X routine. tp - ptr to tty struct to which the tty_buf will become
X associated.
X
X
X EXIT: returns ptr to tty_buf or 0 if there aren't any available.
X tty_buf is removed from the free list and inserted into the used list
X which may make tty_used and tty_free change values.
X*/
X
Xstatic struct tty_buf *get_ttybuf(tp)
X struct tty *tp;
X{
X struct tty_buf *tbp,*next,*last;
X int cnt;
X unchar *chr;
X
X if (tty_free == 0)
X {
X garbage_collect(tbp);
X if (tty_free == 0)
X return 0;
X }
X
X tbp = tty_free;
X
X if (tbp->next == tbp)
X tty_free = 0;
X else
X {
X tbp->next->last = tbp->last;
X tbp->last->next = tbp->next;
X tty_free = tbp->next;
X }
X
X tbp->ttyp = tp;
X setcols(tbp,COLUMNS);
X tbp->dorefresh = tbp->readsleep = NO;
X
X#if !MULTILB
X get_ledbuf(tbp);
X#else
X tbp->lbp = 0;
X#endif
X
X next = tty_used;
X if (next == 0)
X tbp->next = tbp->last = tbp;
X#if INKERNEL
X else
END_OF_FILE
if test 44477 -ne `wc -c <'cled.c.1'`; then
echo shar: \"'cled.c.1'\" unpacked with wrong size!
fi
# end of 'cled.c.1'
fi
if cat cled.c.1 cled.c.2 >cled.c
then
echo 'cled.c rebuilt'
rm cled.c.[12]
else
echo 'trouble concatenating cled.c.[12]'
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Piercarlo "Peter" Grandi | ARPA: pcg%uk.ac.aber.cs at nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth | UUCP: ...!mcsun!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg at cs.aber.ac.uk
More information about the Comp.unix.i386
mailing list