Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_3_19910112
-
unix-stuff/ccmdmd.c
There are no other files named ccmdmd.c in the archive.
/* Machine dependent code for Unix systems -- Use preprocessor
** conditionals for peculiarities of particular systems, but
** PLEASE -- Avoid nesting preprocessor conditionals!
**/
#ifdef V7
#include <sys/types.h> /* needed by file.h on V7 */
#endif
#include <sgtty.h>
#include <sys/file.h> /* for open flags */
#include <stdio.h> /* for FILE */
#include "ccmd.h" /* get ccmd symbols */
#include "cmfncs.h" /* and internal symbols */
/* cmrpjmp
**
** Purpose:
** Automatic reparse handler, installed via the cmsetrp macro from
** ccmd.h. If this handler is installed in a CSB for which a reparse
** is needed, it will perform a longjmp to restart execution at the
** point following the installing cmsetrp invocation. This point
** should be following the call to cmini that set up parsing for
** the current command line, and before the comnd call for the first
** field in the command.
**
** Input arguments: None
** Output arguments: None
** Returns: Nothing
**/
jmp_buf cmrpjb; /* global jump buffer for autoreparse */
cmrpjmp()
{
longjmp(cmrpjb,1); /* do the jump */
return(CMxNOAR); /* if it returns, it failed */
}
/* cmerjmp, cmerjnp
**
** Purpose:
** Automatic parse error handler, much like the automatic reparse
** handler described above. The cmseter macro should be invoked
** just prior to issuing a prompt. When a parsing error
** subsequently occurs (that is, the parse function is about to
** return anything but CMxOK), cmperr will be called to print the
** error, and then execution will jump back to the site of the macro
** invocation. When the automatic error handler is installed, the
** user program can ignore the codes returned by parse, since they
** will always be CMxOK. CSB field _cmerr may be examined to see
** whether the the prior command line was terminated by an error,
** and if so, which error.
**
** Note: Reparse situations will be handled by the error handler if
** no reparse handler has been installed.
**
** Cmerjnp is the same as cmerjmp, except that the error message is
** not printed.
**
** Input arguments: None.
** Output arguments: None.
** Returns: Nothing.
**/
jmp_buf cmerjb; /* global jump buffer */
cmerjmp(ret)
int ret; /* code that triggered the handler */
{
cmperr(ret); /* issue error message */
longjmp(cmerjb,1); /* take the jump */
return(CMxNOAE); /* failed */
}
cmerjnp(ret)
int ret; /* code that triggered the handler */
{
longjmp(cmerjb,1); /* take the jump */
return(CMxNOAE); /* failed */
}
/*
** Machine-dependent IO routines... Generally, a file descriptor is
** supplied as an argument to the calls.
**/
static int autowr; /* TRUE if automatic wrap at eol */
static int li; /* lines on screen */
static char tcapent[1024]; /* complete termcap entry */
static char tcarea[100]; /* decoded termcap entries */
static char *nl,*cr,*cl,*ce,*up; /* pointers to decoded entries */
int outc(); /* output routine for tputs */
char *tgetstr(); /* termlib routine returns string */
/* cmgetc - get a character from the input source. Return standard return
* code.
*/
int cmgetc(c,fd)
char *c; /* pointer where char is placed */
FILE * fd; /* input file descriptor */
{
int cc; /* value from read */
if (cmcsb._cmoj != NULL)
cmflsh(cmcsb._cmoj); /* flush pending output */
if (fd == NULL) /* no file descriptor. EOF */
return(CMxEOF);
*c = getc(fd);
if (*c == EOF)
return(CMxEOF); /* end of file */
else
return(CMxOK); /* good read */
}
/* cmputc - Output a single character to the terminal */
cmputc(c,fd)
char c; /* char to output */
FILE * fd; /* output filedesc */
{
if (fd != NULL) {
putc(c,fd);
if (c == '\n')
cmflsh(fd);
}
}
/* cmputs - Output null-terminated string to the terminal */
cmputs(s,fd)
char *s; /* output string */
FILE *fd; /* output filedesc */
{
while(*s != '\0')
cmputc(*s++,fd);
}
/* cmcr - Move to the beginning of the current line */
cmcr(fd)
FILE * fd; /* output filedesc */
{
cmputs(cr,fd); /* use term specific sequence */
}
/* cmnl - Output a newline sequence to the comman stream */
cmnl(fd)
FILE *fd; /* output filedesc */
{
cmputs(nl,fd); /* use term-specific sequence */
}
/* cmflsh - flush output on fd */
cmflsh(fd)
FILE *fd;
{
if (fd != NULL)
fflush(fd);
}
/* cmwrap - Make sure that cursor wraps when it is required */
cmwrap(fd)
FILE * fd; /* output filedesc */
{
if (!autowr)
cmnl(fd); /* newline if not automatic */
}
/* cmcls - Clear the screen. Current IOJ value in the CSB is used for
** character output. Only invoked if that IOJ is for a CRT terminal.
** Returns TRUE iff the operation succeeds.
**/
int
cmcls()
{
if (cl == NULL)
return(FALSE); /* no clear screen sequence */
else {
tputs(cl,li,outc); /* output the clear sequence */
return(TRUE);
}
}
/* cmceol - Clear to end of line. Current IOJ value in the CSB is
** used for character output. Only invoked if that IOJ is for a CRT
** terminal. Returns TRUE iff the operation succeeds.
**/
cmceol()
{
if (ce == NULL)
return(FALSE); /* no ceol sequence */
else {
tputs(ce,1,outc); /* else do the operation */
return(TRUE);
}
}
/* cmupl - Moves up on line in the display without changing column
** position. Should not wrap to bottom of screen or cause destructive
** downward scrolling. Current IOJ value in the CSB is used for
** character output. Only invoked if that IOJ is for a CRT terminal.
** Returns TRUE if the operation succeeds.
*/
cmupl()
{
if (up == NULL)
return(FALSE); /* no upline sequence */
else {
tputs(up,1,outc); /* else do the operation */
return(TRUE);
}
}
/* cmcpos - Returns the current column position on the display.
** We just assume the ccmd package is correct, since there's
** no facility in termlib for extracting column position, and
** the price for never knowing the cursor position is too high
** (really ugly user interface due to many blank lines).
**/
int
cmcpos()
{
return(cmcsb._cmcol);
}
/* cmflush - Flush all pending input on the input source */
cmflush(fd)
FILE *fd;
{
if (fd != NULL) {
if (isatty(fileno(fd))) /* if it's a terminal */
ioctl(fileno(fd),TIOCFLUSH,NULL); /* flush input and output */
fd->_cnt = 0; /* flush stdio IOBUF. */
}
}
/* cmtset - Initialize the source terminal, as currently set in the
** CSB. If the file is a terminal, a termcap entry is obtained and
** examined to see whether or not it is a hardcopy terminal. If not,
** various control strings are read from the termcap entry and saved
** for screen operations. In any case, terminals are placed in cbreak
** mode without echoing, and INT and TSTP signals are caught to
** prevent the terminal remaining in a funny state upon exit, and to
** place it back into the required state upon continuation.
**/
cmtset()
{
int ofd, ifd;
char *areap = tcarea; /* pointer to termcap decoding area */
char *ttype; /* terminal type */
char *gttype();
if (cmcsb._cmoj != NULL)
ofd = fileno(cmcsb._cmoj); /* input file descriptor */
if (cmcsb._cmij != NULL)
ifd = fileno(cmcsb._cmij); /* output file designator */
if (cmcsb._cmoj != NULL && isatty(ofd)) { /* check if it is a terminal */
cmcsb._cmflg |= CM_TTY; /* yup */
ttype = gttype(ofd); /* get the terminal type name */
if (tgetent(tcapent,ttype) != 1) { /* get termcap entry */
cmcsb._cmflg &= ~CM_CRT; /* no luck... assume hardcopy */
cmcsb._cmcmx = 79; /* use default max column */
nl = "\n"; /* and set default newline */
cr = "\r"; /* and return sequences */
}
else if (cmcsb._cmoj != NULL) {
if (tgetflag("hc")) /* hardcopy indicated? */
cmcsb._cmflg &= ~CM_CRT; /* yup, note it */
else {
cmcsb._cmflg |= CM_CRT; /* else flag a crt */
cl = tgetstr("cl",&areap); /* get clear screen sequence */
ce = tgetstr("ce",&areap); /* and clear end-of-line */
up = tgetstr("up",&areap); /* and upline sequence */
}
nl = tgetstr("nl",&areap); /* alwasy get newline sequence */
if (nl == NULL)
nl = "\n"; /* default if not specified */
cr = tgetstr("cr",&areap); /* get return sequence */
if (cr == NULL)
cr = "\r"; /* or set default */
autowr = tgetflag("am"); /* check for autowrap */
li = tgetnum("li"); /* get number of lines */
if (li == -1) /* no such entry? */
li = 24; /* use default */
cmcsb._cmcmx = tgetnum("co"); /* get col count */
if (cmcsb._cmcmx == -1)
cmcsb._cmcmx = 79; /* use default if not given */
else
cmcsb._cmcmx--; /* else drop to max col position */
}
if (cmcsb._cmij != NULL && isatty(ifd)) {
raw(ifd); /* set up the terminal properly */
intson(); /* install our interrupt handlers */
}
}
else {
if (cmcsb._cmij != NULL && isatty(ifd)) {
raw(ifd); /* set up the terminal properly */
intson(); /* install our interrupt handlers */
}
else {
cmcsb._cmflg &= ~(CM_TTY | CM_CRT); /* not a tty, so not a crt either */
cmcsb._cmcmx = 79; /* and just use default width */
}
}
}
/* cmtend - Clean up after prior input source */
cmtend()
{
int fd;
if (cmcsb._cmij != NULL) {
fd = fileno(cmcsb._cmij); /* file desc to shut down */
if (cmcsb._cmflg & CM_TTY) {
unraw(fd); /* reset former tty params */
intsoff(); /* remove our interrupt handlers */
}
}
}
/* gttype - Return terminal type name for given tty file descriptor
** Auxiliary routine for cmtset
**/
static char *
gttype(fd)
int fd;
{
char *type; /* type name of terminal */
char *name; /* terminal name */
char *cname; /* controlling terminal name */
int cttyfd; /* controlling terminal file desc */
int ctty; /* TRUE if fd is controlling tty */
FILE *typedb; /* stream for ttytype database */
char typelin[80]; /* line from ttytype database */
char *typecp; /* pointer into type db entry */
extern char *ttyname(), *getenv();
cttyfd = open("/dev/tty",O_RDWR,0); /* open the controlling tty */
if (cttyfd < 0)
ctty = FALSE; /* bad open - assume not ctty */
else {
name = ttyname(fd); /* get the terminal name */
cname = ttyname(cttyfd); /* and controlling tty name */
if (strcmp(name,cname) == 0) /* same? */
ctty = TRUE; /* yup, it is ctrl tty */
else
ctty = FALSE; /* nope, some other tty */
close(cttyfd); /* no more use for this */
}
/* */
if (ctty) { /* controlling terminal? */
type = getenv("TERM"); /* yup, use environment var */
if (type != NULL)
return(type); /* give it back if successful */
}
name += 5; /* skip the "/dev/" prefix */
typedb = fopen("/etc/ttytype","r"); /* open type database */
if (typedb == NULL)
return("unknown"); /* give up if bad open */
while (fgets(typelin,80,typedb) != NULL) { /* scan the database */
typecp = typelin;
while ((*typecp++) != SPACE); /* scan for space in entry */
*(typecp-1) = NULCHAR; /* change it to null */
if (strcmp(name,typecp) == 0) { /* this our entry? */
fclose(typedb); /* yup, shut database */
return(typelin); /* and return type name */
}
}
fclose(typedb); /* not found... close database */
return("unknown"); /* and give default */
}
/* auxiliary routines to take terminals into and out of raw mode */
static struct sgttyb ttyblk, ttysav; /* tty parameter blocks */
#ifdef BSD
static struct ltchars ltc,ltcsav; /* local special chars for new */
/* tty driver */
#endif
/* raw - put the terminal into raw (actually cbreak) mode, turn off
** echoing and output translations, and extract the output speed for
** the termcap library. On BSD unix systems, literal-next processing
** is also disabled.
**/
static
raw(fd)
int fd;
{
extern short ospeed; /* declared in termlib */
ioctl(fd,TIOCGETP,&ttysav); /* get original parameters */
ttyblk = ttysav; /* copy into new parameter block */
ospeed = ttysav.sg_ospeed; /* save output speed for termlib */
ttyblk.sg_flags &= ~(RAW | ECHO | LCASE); /* no echoing or xlates */
ttyblk.sg_flags |= CBREAK | CRMOD; /* single character reads */
ioctl(fd,TIOCSETN,&ttyblk); /* set params, leave typeahead */
#ifdef BSD
ioctl(fd,TIOCGLTC,<c); /* get current local special chars */
ltcsav = ltc; /* copy it for later restore */
ltc.t_lnextc = -1; /* disable literal-next */
ioctl(fd,TIOCSLTC,<c); /* set the new chars in place */
#endif
}
/* unraw - restore the tty modes in effect before raw was performed. */
static
unraw(fd)
int fd;
{
ioctl(fd,TIOCSETP,&ttysav); /* put back saved params */
#ifdef BSD
ioctl(fd,TIOCSLTC,<csav); /* restore local special chars */
#endif
}
/* outc - aux routine to be passed to termlib routines - output one char */
PASSEDSTATIC
outc(c)
char c;
{
FILE *fd = cmcsb._cmoj; /* get output filedesc */
if (fd != NULL)
putc(c,fd); /* do the write */
}
/* intson - Install our interrupt handlers for INT and STOP, so
** any terminal settings we have installed will be undone before
** the program exits. Any handlers that are already installed
** are left in place. Those handlers should call cmdone if
** they expect to exit with the terminal set correctly.
**/
#include <signal.h> /* get signal symbols */
#ifdef V7 /* used improve calls in version 7 */
#define signal sigsys
#endif
#define mask(sig) (1 << ((sig)-1))
static
intson()
{
int sighand(); /* forward decl of our handler */
int oldmask; /* signal mask before we play */
int (*oldhand)(); /* old handler */
#ifdef BSD
oldmask = sigblock(mask(SIGINT) | mask(SIGTSTP)); /* hold these */
#endif
oldhand = signal(SIGINT,sighand); /* install our handler, get prior */
if (oldhand != SIG_DFL) /* did they have something? */
signal(SIGINT,oldhand); /* yup, leave it there */
oldhand = signal(SIGTSTP,sighand); /* install ours for TSTP too */
if (oldhand != SIG_DFL)
signal(SIGTSTP,oldhand); /* but leave theirs intact */
#ifdef BSD
sigsetmask(oldmask); /* now unblock the signals */
#endif
}
/* intsoff - Remove our interrupt handlers. If we remove something
** that isn't ours, put it back.
**/
static
intsoff()
{
int sighand(); /* forward decl of our handler */
int oldmask; /* sig mask prior to our diddling */
int (*oldhand)(); /* prior handler for a signal */
#ifdef BSD
oldmask = sigblock(mask(SIGINT) | mask(SIGTSTP)); /* block our sigs */
#endif
oldhand = signal(SIGINT,SIG_DFL); /* remove INT handler */
if (oldhand != sighand)
signal(SIGINT,oldhand); /* replace if not ours */
oldhand = signal(SIGTSTP,SIG_DFL); /* remove TSTP handler */
if (oldhand != sighand)
signal(SIGTSTP,oldhand); /* replace if not ours */
#ifdef BSD
sigsetmask(oldmask); /* replace old signal mask */
#endif
}
/* sighand - Handler for INT and TSTP signals. We first fix
** the terminal to its normal settings, then remove our handler
** and generate whichever signal invoked us to get the default
** action. If the program is continued, the terminal is adjusted
** again, and our handler is reinstalled. (This should only happen
** with TSTP signals).
**/
static
sighand(sig,code,scp)
int sig,code; /* sig is all we care about */
struct sigcontext *scp;
{
int oldmask; /* prior interrupt mask */
long getpid(); /* pids are long */
cmtend(); /* fix the terminal */
#ifdef BSD
oldmask = sigsetmask(0); /* let our signal get through */
#endif
cmnl(stdout); /* move to new line for looks */
kill(getpid(),sig); /* get the default action */
cmtset(); /* redo the terminal if continued */
#ifdef BSD
sigsetmask(oldmask); /* set mask back to before */
#endif
}
/* ctty, cttycls - Ctty opens the controlling terminal and returns a
** file descriptor for it. After the first call, it just returns the
** file descriptor opened previously. Cttycls closes the file
** descriptor opened by ctty, after which another call to ctty will
** open another one.
**/
static int ttyfd = -1;
static int
ctty()
{
if (ttyfd == -1)
ttyfd = open("/dev/tty",O_RDWR,0);
return(ttyfd);
}
static
cttycls()
{
if (ttyfd != -1)
close(ttyfd);
ttyfd = -1;
}