Google
 

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,&ltc);		/* get current local special chars */
  ltcsav = ltc;				/* copy it for later restore */
  ltc.t_lnextc = -1;			/* disable literal-next */
  ioctl(fd,TIOCSLTC,&ltc);		/* 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,&ltcsav);		/* 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;
}