ftp.nice.ch/pub/next/tools/frontends/Emacs.3.0.1.s.tar.gz#/Emacs-3.0.1/etermSupport.c

This is etermSupport.c in view mode; [Download] [Up]

/* Supporting c code for the EtermView class.

   For legal stuff see the file COPYRIGHT.  */

#include <libc.h>
#include <appkit/nextstd.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/socket.h>

#include "defaults.h"
#include "etermSupport.h"

/* Some random lab's phone number.  Ask Tom Lord.  */
#define FIB20 6765

extern int errno;

/* Given the current environment, give us a new environment suitable for an
   emacs process with an event server on port 'eventportno' */
char **
patch_env (char **currentEnv, int eventportno)
{
  static char term[] = "TERM=eterm";
  static char termcap[] = "TERMCAP=69|eterm|Terminal emulator for Gnu-emacs:co#80:li#24:cm=^u%d^u%d.:IC=^u%d_:DC=^u%d^d:AL=^u%d^o:DL=^u%d^k:bc=^b:bl=^g:cd=^[k:ce=^k:ch=^u%d.:cl=^[c:cr=^a:do=^n:im=^i:ei=^i:le=^b:mi:ms:nd=^f:nl=^j:se=^s:so=^s:up=^p:am:km:";
  char *eventhost;
  static char eventport[80];
  char **newEnv;
  int envSize, x, y;
  char hostname[1024];

  if (gethostname (hostname, sizeof (hostname)) == -1)
    {
      NXLogError ("gethostname: %s", strerror (errno));
      exit (1);
    }

  eventhost = malloc (strlen (hostname) + 12);
  strcpy (eventhost, "EVENT_HOST=");
  strcat (eventhost, hostname);

  sprintf (eventport, "EVENT_PORT=%d", eventportno);

  for (envSize = 0; currentEnv[envSize] != NULL; envSize++);
  newEnv = (char **) malloc (sizeof (char *) *(envSize + 5));
  for (x = y = 0; x < envSize; x++)
    if (strncmp (currentEnv[x], "TERM=", 5)
	&& strncmp (currentEnv[x], "TERMCAP=", 8)
	&& strncmp (currentEnv[x], "EVENT_HOST=", 11)
	&& strncmp (currentEnv[x], "EVENT_PORT=", 11))
      newEnv[y++] = currentEnv[x];
  newEnv[y++] = term;
  newEnv[y++] = termcap;
  newEnv[y++] = eventhost;
  newEnv[y++] = eventport;
  newEnv[y] = NULL;
  return newEnv;
} /* patch_env */

/* Create the event server socket for an emacs process.  Store the port
   number in the int ponted to by eventportno.  */
int
create_server_socket (int *eventportno)
{
  int EventServerSocket;
  struct sockaddr_in name;
  int portno = FIB20;

  if ((EventServerSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
      NXLogError ("socket: %s", strerror (errno));
      exit (1);
    }

  while (portno < FIB20 + 100)
    {
      name.sin_family = AF_INET;
      name.sin_port = htons (portno);
      name.sin_addr.s_addr = INADDR_ANY;

      if (bind (EventServerSocket, (struct sockaddr *) &name, sizeof (name))
	  == -1)
	{
	  portno++;
	  continue;
	}
      if (listen (EventServerSocket, 1) == -1)
	{
	  NXLogError ("listen: %s", strerror (errno));
	  exit (1);
	}
      *eventportno = portno;
      return EventServerSocket;
    }
  NXLogError ("bind: %s", strerror (errno));
  exit (1);
} /* create_server_socket */

/* Accept a connection on an event server socket.  */
int
accept_server_connection (int serversocket)
{
  int s;
  struct sockaddr_in name;
  int namelen = sizeof (name);

  if ((s = accept (serversocket, (struct sockaddr *) &name, &namelen)) == -1)
    return -1;
  return s;
} /* accept_server_connection */

/* The create_channel code is stolen from h19.  "it should be replaced".  */
char  ptcname[] = "/dev/ptyXX";
char  ptyname[] = "/dev/ttyXX";

/* Grab a pty/tty pair for running a child emacs process.  */
void
create_channel (int *master, int *slave, int *ptynumber)
{
  int MasterChannel, PtyNumber, ShellChannel = -1;
  int pid;
  char c;

  pid = getpid ();
  if (setpgrp (0, pid) < 0)
    NXLogError ("setpgrp: %s", strerror (errno));

  /* Remove the current controling terminal -- will create a new one.  */
  {
    int   fd;
    fd = open ("/dev/tty", 2);
    if (fd >= 0)
      {
	if (ioctl (fd, TIOCNOTTY, NULL) < 0)
	  NXLogError ("ioctl (TIOCNOTTY): %s", strerror (errno));
	close (fd);
      }
  }

  /* Find pseudo-teletype for subchannel to shell.  */
  for (c = 'p'; c <= 'r'; c++)
    {
      ptcname[strlen ("/dev/pty")] = c;
      ptcname[strlen ("/dev/ptyX")] = '0';
      for (PtyNumber = 0; PtyNumber < 16; PtyNumber++)
	{
	  ptcname[strlen ("/dev/ptyX")] = "0123456789abcdef"[PtyNumber];
	  MasterChannel = open (ptcname, 2);
	  if (MasterChannel < 0)
	    continue;
	  ptyname[strlen ("/dev/tty")] = c;
	  ptyname[strlen ("/dev/ttyX")] = "0123456789abcdef"[PtyNumber];
	  ShellChannel = open (ptyname, 2);
	  if (ShellChannel >= 0)
	    goto gotpty;
	  close (MasterChannel);
	}
    }

 gotpty:
  if (MasterChannel < 0 || ShellChannel < 0)
    {
      NXLogError ("Can't connect subchannel");
      exit (1);
    }

  /* Adjust terminal driver for Master Channel.  */
  {
    int	 nonBlock = 1;
    /* Exclusive use of Master.  */
    if (ioctl (MasterChannel, FIOCLEX, NULL) < 0)
      NXLogError ("ioctl (FIOCLEX): %s", strerror (errno));
    if (ioctl (MasterChannel, FIONBIO, &nonBlock) < 0)
      NXLogError ("ioctl (FIONBIO): %s", strerror (errno));
  }

  /* Adjust terminal driver for Shell Channel.  */
  {
    int line_discipline = NTTYDISC;
    int local_mode;
    struct sgttyb  ttystate;

    if (ioctl (ShellChannel, TIOCHPCL, NULL) < 0)
      perror ("TIOCHPCL");
    if (ioctl (ShellChannel, TIOCSETD, &line_discipline) < 0)
      perror ("TIOCSETD");
    if (ioctl (ShellChannel, TIOCGETP, &ttystate) < 0)
      perror ("TIOCGETP");
    ttystate.sg_flags = CRMOD | ANYP | ECHO;

    /* CRMOD - tread CR like LF; output of LF is CR/LF 
       XTABS - change TABS to sequence of blanks 
       ANYP - Any parity okay
       ECHO - echo characters (full duplex)  */
    ttystate.sg_erase = '\010';
    if (ioctl (ShellChannel, TIOCSETP, &ttystate) < 0)
      perror ("TIOCSETP");
    if (ioctl (ShellChannel, TIOCLGET, &local_mode) < 0)
      perror ("TIOCLGET");

    /* LCRTBS - CRT back space to ^H
       LCRTERA - backspace-space-backspace
       LCRTKIL - erase as LCRTERA for line kill too
       LCTLECH - echo non-printing characters as ^X.  */
    local_mode |= LCRTBS | LCRTKIL | LCRTERA | LCTLECH;
    if (ioctl (ShellChannel, TIOCLSET, &local_mode) < 0)
      perror ("TIOCLSET");
  }
  *master = MasterChannel;
  *slave = ShellChannel;
  *ptynumber = PtyNumber;
} /* create_channel */

/* Reap zombie processes.  If any child processes stopped themselves, give
   them a kick in the pants.  */
static void
ShellDone ()
{
  int pid;
  union wait stat;

  while ((pid = wait3 (&stat, WUNTRACED | WNOHANG, 0 )) > 0)
    {
      if (WIFSTOPPED (stat))
	kill (pid,SIGCONT);
    }
} /* ShellDone */

/* Fork and exec the child emacs.  */
void
fork_shell (char *name, char **args, char **env, int channel)
{
  int pid;

  signal (SIGCLD, ShellDone);
  signal (SIGTTOU, SIG_IGN);

  if ((pid = fork ()) < 0)
    {
      NXLogError ("fork: %s", strerror (errno));
      exit (1);
    }

  if (pid == 0)
    {
      int i;
      int cpid;

      cpid = getpid ();
      if (ioctl (channel, TIOCSPGRP, &cpid) < 0)
	perror ("TIOCSPGRP");
      if (setpgrp (0, cpid) < 0)
	perror ("setpgrp");

      dup2 (channel, 0);
      dup2 (channel, 1);
      for (i = getdtablesize (); i > 2; i--)
	close (i);

      execve (name, args, env);
      NXLogError ("%s: %s", name, strerror (errno));
      execve (DEFAULT_EMACS_PATH, args, env);
      NXLogError ("%s: %s", DEFAULT_EMACS_PATH, strerror (errno));
      exit (1);
    }
} /* fork_shell */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.