home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
mm
/
mm-ccmd-0.91-20031009.tar.gz
/
mm-ccmd-0.91-20031009.tar
/
work
/
ccmd
/
ccmdmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-09-17
|
28KB
|
1,041 lines
/*
Copyright (c) 1986, 2002 by The Trustees of Columbia University in
the City of New York. Permission is granted to any individual or
institution to use, copy, or redistribute this software so long as it
is not sold for profit, provided this copyright notice is retained.
Author: Andrew Lowry
*/
/* Machine dependent code for Unix systems -- Use preprocessor
** conditionals for peculiarities of particular systems, but
** PLEASE -- Avoid nesting preprocessor conditionals!
**/
#include "ccmdlib.h"
#include "cmfncs.h" /* and internal symbols */
#include <string.h> /* For index etc */
#include <errno.h> /* For errno */
/* Terminal driver defs */
#if HAVE_TERMIOS
# include <termios.h>
#elif HAVE_TERMIO
# include <sys/termio.h>
#else
# include <sgtty.h>
#endif
/* Signal handling defs, very system-dependent */
#include <signal.h>
/*
* On some systems, signal handlers are defined as returning (void).
*/
#if CCMD_OS_BSD44
# define ccmdsigval_t sig_t
# define SIG void
#elif CCMD_OS_LINUX
typedef void (*ccmdsigval_t)(int);
# define SIG void
#elif HAVE_VOIDSIG
typedef void (*ccmdsigval_t)();
# define SIG void
#else
typedef int (*ccmdsigval_t)();
# define SIG int
#endif
/*
* Must now allow for signal sets
*/
#if HAVE_SIGSETS
# define ccmdsigset_t sigset_t
# define ccmdsigemptyset(set) sigemptyset(set)
# define ccmdsigfillset(set) sigfillset(set)
# define ccmdsigaddset(set,s) sigaddset(set,s)
# define ccmdsigdelset(set,s) sigdelset(set,s)
# define ccmdsigismember(set,s) sigismember(set,s)
#else
# ifndef sigmask
# define sigmask(m) (1 << ((m) - 1))
# endif
# define ccmdsigset_t unsigned long
# define ccmdsigemptyset(set) (*(set) = 0)
# define ccmdsigfillset(set) (*(set) = ~0L)
# define ccmdsigaddset(set,s) (*(set) |= sigmask(s))
# define ccmdsigdelset(set,s) (*(set) &= ~sigmask(s))
# define ccmdsigismember(set,s) (*(set) & sigmask(s))
#endif
/* Local forward decls */
static char *strindex(char *src, char *str);
static char *gttype(int fd);
static raw(int fd);
static unraw(int fd);
PASSEDSTATIC int outc(int c);
static void intson(void);
static void intsoff(void);
/* 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,str,flags)
int ret; /* code that triggered the handler */
char *str;
int flags;
{
if (str) return(cmermsg(str,flags));
cmperr(ret,flags); /* issue error message */
longjmp(cmerjb,1); /* take the jump */
return(CMxNOAE); /* failed */
}
cmermsg(str,flags)
char *str; /* error msg */
int flags;
{
cmpemsg(str,flags); /* 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 */
}
/* KLH: This appears to help implement cmsetbl() but is only
defined for BSD and is never used by MM.
*/
#ifdef CCMD_OS_BSD
/*
* if handling nonblocking I/O, and a EWOULDBLOCK error comes up
* Then jump to the point set with a cmsetbl() call.
* The user then could wait for input.
*/
jmp_buf cmbljb; /* global jump buffer */
cmbljmp(ret)
int ret; /* code that triggered the handler */
{
if (errno != EWOULDBLOCK)
return(ret);
longjmp(cmbljb,1); /* take the jump */
return(CMxNOAE); /* failed */
}
#endif
/*
** 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 = "\n";
static char *cr = "\r";
static char *cl,*ce,*up; /* pointers to decoded entries */
static char *le,*nd,*down;
char *tgetstr(); /* termlib routine returns string */
/* cmgetc - get a character from the input source. Return standard return
* code.
*/
int cmgetc(c,fd)
int *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);
#if 0 /* KLH: yeech. What to replace with? */
if (fd->_cnt == 0 && (cmcsb._cmflg & CM_ITTY))
cmselect(fileno(fd));
#endif
*c = cc = getc(fd);
if (cc == 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 */
if (cmcsb._cmoj)
fflush(cmcsb._cmoj);
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);
}
}
cmdownl()
{
int oldcrmod;
if (down == NULL)
return(FALSE); /* no upline sequence */
else {
if (cmcsb._cmoj) {
oldcrmod = crmod(FALSE);
tputs(down,1,outc); /* else do the operation */
if (cmcsb._cmoj)
fflush(cmcsb._cmoj);
crmod(oldcrmod);
return(TRUE);
}
}
}
cmleft()
{
if (le == NULL)
return(FALSE); /* no move left sequence */
else {
tputs(le,1,outc); /* else do the operation */
cmcsb._cmcol--;
return(TRUE);
}
}
cmright()
{
if (nd == NULL)
return(FALSE); /* no move right sequence */
else {
tputs(nd,1,outc); /* else do the operation */
cmcsb._cmcol++;
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 */
#if HAVE_TERMIOS
tcflush(fileno(fd), TCIOFLUSH);
#else
# if HAVE_TERMIO && !defined(TIOCFLUSH)
# define TIOCFLUSH TCFLSH
# endif
ioctl(fileno(fd),TIOCFLUSH,NULL); /* flush input and output */
#endif
}
#if 0 /* KLH: yeech!!! */
fd->_cnt = 0; /* flush stdio IOBUF. */
#elif HAVE_FPURGE
fpurge(fd); /* Reset stdio buffer */
#endif
}
}
/* 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 */
int tret;
if (cmcsb._cmoj != NULL)
ofd = fileno(cmcsb._cmoj); /* input file descriptor */
if (cmcsb._cmij != NULL)
ifd = fileno(cmcsb._cmij); /* output file designator */
cmcsb._cmflg &= ~CM_TTY;
if (cmcsb._cmoj != NULL && isatty(ofd)) { /* check if it is a terminal */
cmcsb._cmflg |= CM_OTTY; /* yup */
ttype = gttype(ofd); /* get the terminal type name */
if (tcapent[0] == '\0')
tret = tgetent(tcapent,ttype); /* get termcap entry */
else
tret = 1;
if (tret != 1) {
cmcsb._cmflg2 &= ~CM_CRT; /* no luck... assume hardcopy */
cmcsb._cmcmx = 79; /* use default max column */
cmcsb._cmwrp = 79; /* and wrap column */
nl = "\n"; /* and set default newline */
cr = "\r"; /* and return sequences */
}
else if (cmcsb._cmoj != NULL) {
if (tgetflag("hc")) /* hardcopy indicated? */
cmcsb._cmflg2 &= ~CM_CRT; /* yup, note it */
else {
cmcsb._cmflg2 |= CM_CRT; /* else flag a crt */
}
cmtsize(); /* setup term size & termcap vars */
cmcsb._cmwrp = cmcsb._cmcmx; /* set up autowrap column */
}
if (cmcsb._cmij != NULL && isatty(ifd)) {
cmcsb._cmflg |= CM_ITTY; /* yup */
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; /* not a tty, so not a crt either */
cmcsb._cmflg2 &= ~CM_CRT;
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 */
}
}
}
/*
* cmtsize()
* set up terminal size. try using TIOCGWINSZ if possible. If not set,
* use termcap entry. If ioctl() succeeds, fix up termcap entry, so inferior
* processes inherit correctly.
*/
cmtsize()
{
int li = -1, co = -1;
#ifdef TIOCGWINSZ
struct winsize w;
if (ioctl(fileno(cmcsb._cmoj), TIOCGWINSZ, &w) == 0) {
if (w.ws_col > 0 && cmcsb._cmcmx != w.ws_col) {
co = cmcsb._cmcmx = w.ws_col;
}
if (w.ws_row > 0 && cmcsb._cmrmx != w.ws_row) {
li = cmcsb._cmrmx = w.ws_row;
}
}
#else /* TIOCGWINSZ */
#ifdef TIOCGSIZE
struct ttysize t;
if (ioctl(fileno(cmcsb._cmoj), TIOCGSIZE, &t) == 0) {
if (t.ts_col > 0 && cmcsb._cmcmx != t.ts_col) {
co = cmcsb._cmcmx = t.ts_col;
}
if (t.ts_row > 0 && cmcsb._cmrmx != t.ts_row) {
li = cmcsb._cmrmx = t.ts_row;
}
}
#endif /* TIOCGSIZE */
#endif /* !TIOCGWINSZ */
if (co <= 0)
cmcsb._cmcmx = tgetnum("co"); /* get col count */
if (cmcsb._cmcmx <= 0)
cmcsb._cmcmx = 79; /* use default if not given */
else
cmcsb._cmcmx--; /* else drop to max col position */
if (li <= 0) /* */
cmcsb._cmrmx = tgetnum("li"); /* get row count */
if (cmcsb._cmrmx == -1)
cmcsb._cmrmx = 24; /* or use default if necesary */
li = --cmcsb._cmrmx;
tc_setsize(cmcsb._cmrmx+1,cmcsb._cmcmx+1);
}
/*
* set the "li" and "co" entries in the termcap entry
*/
tc_setsize(li, co) {
char buf[1024], *p1 = NULL, *p2=NULL, *p3=NULL, *p4=NULL;
p1 = strindex(tcapent,"co#"); /* find num cols */
if (p1) {
p2 = index(p1+1,':'); /* and the end of it. */
}
p3 = strindex(tcapent,"li#"); /* find num lines */
if (p3) {
p4 = index(p3+1,':'); /* and the end of it */
}
if (p3)
*p3 = '\0';
if (p1)
*p1 = '\0';
if (p2)
*(p2++) == '\0';
else p2 = "";
if (p4)
*(p4++) == '\0';
else
p4 = "";
/* build new termcap string */
sprintf(buf,"%sco#%d:%sli#%d:%s", tcapent, co, p2, li, p4);
strcpy(tcapent, buf);
setenv("TERMCAP", tcapent, TRUE); /* put it in the environment. */
tc_setents(tcarea);
}
tc_setents(areap)
char *areap;
{
if (cmcsb._cmflg2 & CM_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 */
le = tgetstr("le",&areap); /* move left */
nd = tgetstr("nd",&areap); /* move right */
down = tgetstr("do",&areap); /* move down */
if (le == NULL)
le = "\b"; /* default if not specified */
}
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 = cmcsb._cmrmx;
}
/*
* search for an embedded string
*/
static char *
strindex(char *src, char *str)
{
char *cp = src, *cp1;
while(cp1 = index(cp, *str)) {
if (strncmp(cp1, str, strlen(str)) == 0) {
return(cp1);
}
cp = cp1+1;
}
return(NULL);
}
/* gttype - Return terminal type name for given tty file descriptor
** Auxiliary routine for cmtset
**/
static char *
gttype(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 */
static 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 */
#if HAVE_TERMIOS
static struct termios ttyblk, ttysav;
#elif HAVE_TERMIO
static struct termio ttyblk, ttysav;
#elif HAVE_TERM_BSD
static struct sgttyb ttyblk, ttysav; /* tty parameter blocks */
static struct ltchars ltc,ltcsav; /* local special chars for new */
#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(int fd)
{
#if HAVE_TERMIOS
tcgetattr(fd, &ttysav);
ttyblk = ttysav;
ttyblk.c_lflag &= ~(ICANON|ECHO); /* Make raw-ish */
ttyblk.c_cc[VINTR] = 003; /* interrupt char is control-c */
ttyblk.c_cc[VMIN] = 1;
ttyblk.c_cc[VTIME] = 1;
tcsetattr(fd, TCSADRAIN, &ttyblk);
#elif HAVE_TERMIO
/* KLH: Note that the c_cc index values have CHANGED since the original
** SYSV implementation. Now using symbols, but original values left
** in comments.
*/
ioctl(fd, TCGETA, &ttysav);
ttyblk = ttysav;
ttyblk.c_lflag &= ~(ICANON|ECHO);
ttyblk.c_cc[VINTR/*0*/] = 003; /* interrupt char is control-c */
ttyblk.c_cc[VMIN/*4*/] = 1;
ttyblk.c_cc[VTIME/*5*/] = 1;
ioctl(fd,TCSETAW,&ttyblk); /* set new modes . */
#elif HAVE_TERM_BSD
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; /* single character reads */
ioctl(fd,TIOCSETN,&ttyblk); /* set params, leave typeahead */
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 */
#else
# --ERROR-- no code for raw()
#endif
}
/* unraw - restore the tty modes in effect before raw was performed. */
static
unraw(int fd)
{
#if HAVE_TERMIOS
tcsetattr(fd, TCSADRAIN, &ttysav); /* put back saved params */
#elif HAVE_TERMIO
ioctl(fd,TCSETAW, &ttysav); /* put back saved params */
#elif HAVE_TERM_BSD
ioctl(fd,TIOCSETN,&ttysav); /* put back saved params */
ioctl(fd,TIOCSLTC,<csav); /* restore local special chars */
#else
--ERROR-- no code for unraw()
#endif
}
/* outc - aux routine to be passed to termlib routines - output one char */
PASSEDSTATIC int
outc(int 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.
**/
#ifdef V7 /* used improve calls in version 7 */
#define signal sigsys
#endif
/* Implement our own version of signal().
* Needed because systems vary in how they implement this.
* NetBSD/FreeBSD: SA_RESTART on, SA_RESETHAND off
* Solaris: SA_RESTART off, SA_RESETHAND on
* Ugh!!!
* MM was written assuming the BSD settings.
*/
static ccmdsigval_t
ccmdsignal(int sig, ccmdsigval_t func)
{
#if HAVE_SIGSETS
struct sigaction act, oact;
act.sa_handler = func;
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, sig);/* Suspend this sig during handler */
if (sigaction(sig, &act, &oact) == 0)
return oact.sa_handler;
return (ccmdsigval_t)-1;
#else
return (ccmdsigval_t) signal(sig, func);
#endif
}
static void
intson(void)
{
static SIG sighand(); /* forward decl of our handler */
ccmdsigset_t oldmask; /* sig mask prior to our diddling */
ccmdsigset_t sigs; /* New sig mask */
ccmdsigval_t oldhand; /* old handler */
ccmdsigemptyset(&sigs);
#if defined(SIGTSTP) || defined(SIGWINCH)
(void) ccmdsigaddset(&sigs, SIGINT);
# ifdef SIGTSTP
(void) ccmdsigaddset(&sigs, SIGTSTP);
# endif
# ifdef SIGWINCH
(void) ccmdsigaddset(&sigs, SIGWINCH);
#endif
# if HAVE_SIGSETS
(void) sigprocmask(SIG_BLOCK, &sigs, &oldmask);
# else
oldmask = sigblock(sigs);
# endif
#endif
oldhand = ccmdsignal(SIGINT, (ccmdsigval_t)sighand); /* install our handler, get prior */
if (oldhand != SIG_DFL) /* did they have something? */
ccmdsignal(SIGINT,oldhand); /* yup, leave it there */
#ifdef SIGTSTP
oldhand = ccmdsignal(SIGTSTP, (ccmdsigval_t)sighand); /* install ours for TSTP too */
if (oldhand != SIG_DFL)
ccmdsignal(SIGTSTP,oldhand); /* but leave theirs intact */
#endif /* SIGTSTP */
#ifdef SIGWINCH
oldhand = ccmdsignal(SIGWINCH, (ccmdsigval_t)sighand); /* install ours for WINCH too */
if (oldhand != SIG_DFL)
ccmdsignal(SIGWINCH,oldhand); /* but leave theirs intact */
#endif /* SIGWINCH */
/* now unblock the signals */
#if defined(SIGTSTP) || defined(SIGWINCH)
# if HAVE_SIGSETS
(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)NULL);
# else
sigsetmask(oldmask);
# endif
#endif
}
/* intsoff - Remove our interrupt handlers. If we remove something
** that isn't ours, put it back.
**/
static void
intsoff(void)
{
static SIG sighand(); /* forward decl of our handler */
ccmdsigset_t oldmask; /* sig mask prior to our diddling */
ccmdsigset_t sigs; /* New sig mask */
ccmdsigval_t oldhand; /* prior handler for a signal */
ccmdsigemptyset(&sigs);
#if defined(SIGTSTP) || defined(SIGWINCH)
(void) ccmdsigaddset(&sigs, SIGINT);
# ifdef SIGTSTP
(void) ccmdsigaddset(&sigs, SIGTSTP);
# endif
# ifdef SIGWINCH
(void) ccmdsigaddset(&sigs, SIGWINCH);
#endif
# if HAVE_SIGSETS
(void) sigprocmask(SIG_BLOCK, &sigs, &oldmask);
# else
oldmask = sigblock(sigs);
# endif
#endif
oldhand = ccmdsignal(SIGINT,SIG_DFL); /* remove INT handler */
if (oldhand != (ccmdsigval_t)sighand)
ccmdsignal(SIGINT,oldhand); /* replace if not ours */
#ifdef SIGTSTP
oldhand = ccmdsignal(SIGTSTP,SIG_DFL); /* remove TSTP handler */
if (oldhand != (ccmdsigval_t)sighand)
ccmdsignal(SIGTSTP,oldhand); /* replace if not ours */
#endif
#ifdef SIGWINCH
oldhand = ccmdsignal(SIGWINCH,SIG_DFL); /* remove TSTP handler */
if (oldhand != (ccmdsigval_t)sighand)
ccmdsignal(SIGWINCH,oldhand); /* replace if not ours */
#endif
/* now unblock the signals */
#if defined(SIGTSTP) || defined(SIGWINCH)
# if HAVE_SIGSETS
(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)NULL);
# else
sigsetmask(oldmask);
# endif
#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 SIG
sighand(sig,code,scp)
int sig,code; /* sig is all we care about */
struct sigcontext *scp;
{
ccmdsigset_t oldmask; /* prior interrupt mask */
ccmdsigset_t sigs; /* New sig mask */
#if !HAVE_UNISTD
long getpid(); /* pids are long */
#endif
switch (sig) {
#ifdef SIGWINCH
case SIGWINCH:
cmtsize();
break;
#endif
default:
cmtend(); /* fix the terminal */
# if HAVE_SIGSETS
ccmdsigemptyset(&sigs); /* Set no signals blocked */
(void) sigprocmask(SIG_SETMASK, &sigs, &oldmask);
# else
oldmask = sigsetmask(0);
# endif
#ifdef SIGTSTP
if (sig == SIGTSTP)
cmnl(stdout); /* move to new line for looks */
#endif /* SIGTSTP */
kill(getpid(),sig); /* get the default action */
cmtset(); /* redo the terminal if continued */
# if HAVE_SIGSETS
(void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
# else
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;
}
/* KLH: Only used to disable NL->CR+NL output conversion during
a cursor-move-down sequence (ie cmdownl())
*/
crmod(val)
int val;
{
int oldval;
int fd;
if (cmcsb._cmoj == NULL)
return(-1);
fd = fileno(cmcsb._cmoj);
#if HAVE_TERMIOS
{
struct termios tblk; /* get original parameters */
tcgetattr(fd, &tblk);
oldval = tblk.c_oflag & ONLCR;
if (val)
tblk.c_oflag |= ONLCR; /* Turn on NL to CR-NL (old CRMOD) */
else
tblk.c_oflag &= ~ONLCR; /* Turn off NL to CR-NL (old CRMOD) */
tcsetattr(fd, TCSANOW , &tblk); /* set params, leave typeahead */
}
#elif defined(TIOCSETN) /* For either HAVE_TERMIO or HAVE_TERM_BSD */
{
struct sgttyb ttyblk;
ioctl(fd,TIOCGETP,&ttyblk); /* get original parameters */
oldval = ttyblk.sg_flags & CRMOD;
if (val)
ttyblk.sg_flags |= CRMOD; /* turn on CRMOD */
else
ttyblk.sg_flags &= ~CRMOD; /* turn off CRMOD */
ioctl(fd,TIOCSETN,&ttyblk); /* set params, leave typeahead */
}
#else
oldval = 0;
#endif
return(oldval);
}
cmselect(fd)
int fd;
{
#ifdef FD_SETSIZE
fd_set rfds, efds;
int r;
while(1) {
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(fd, &rfds);
FD_SET(fd, &efds);
r = select(FD_SETSIZE, &rfds, NULL, &efds, NULL);
if (r >= 0 || errno != EINTR)
return;
}
#endif
}