ftp.nice.ch/pub/next/developer/objc/appkit/FrontEndTool.s.tar.gz#/FrontEndTool/etermSupport.c

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

#include <stdio.h>
#include <libc.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.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) {
      perror("gethostname");
      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;
}

/*
 * 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) {
	perror("socket");
	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) {
	    perror("listen");
	    exit(1);
	}

	*eventportno = portno;
	return EventServerSocket;
    }
    perror("bind");
    exit(1);
}

/*
 * 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;
}

void child_setup_tty (int out)
{
  struct sgttyb s;

  ioctl (out, TIOCGETP, &s);
  s.sg_flags |= (ECHO | CRMOD);
  ioctl (out, TIOCSETN, &s);
}

void setup_tty (int out)
{
    struct sgttyb s;

  ioctl (out, TIOCGETP, &s);
  s.sg_flags &= ~(ECHO);
  s.sg_flags |= RAW;
  ioctl (out, TIOCSETN, &s);
}

// Open an available pty, putting descriptor in *ptyv, and return the
// file name of the corresponding tty.  Return 0 if none available.

char ptyname[24];

char * pty (int *ptyv)
{
    struct stat stb;
    register c, i;
    
    for (c = 'p'; c <= 'q'; c++)
	for (i = 0; i < 16; i++)
	    {
	    sprintf (ptyname, "/dev/pty%c%x", c, i);
	    
	    if (stat (ptyname, &stb) < 0)
		return 0;
	    *ptyv = open (ptyname, O_RDWR | O_NDELAY, 0);
	    
	    if (*ptyv >= 0)
		{
		/* check to make certain that both sides are available
		   this avoids a nasty yet stupid bug in rlogins */
		
		ptyname[5] = 't';
		
		if (access (ptyname, 6) != 0)
		    {
		    close (*ptyv);
		    continue;
		    }
		/*
		 * If the following statement is included,
		 * then a 0 length record is EOT, but no other
		 * control characters can be sent down the pty
		 * (e.g., ^S/^Q, ^O, etc.).  If it is not
		 * included, then sending ^D down the pty-pipe
		 * makes a pretty good EOF.
		 */
		return ptyname;
		}
	    }
    return 0;
}

// Grab a pty/tty pair for running a child process.

void create_channel(int *master, int *slave)
{
    int MasterChannel, ShellChannel;
    int pid;
    char *ttyname;

    pid = getpid ();
    if (setpgrp (0, pid) < 0) perror("setpgrp");

    /* remove the current controling terminal -- will create a new one */
    {
    int   fd;
    fd = open ("/dev/tty", O_RDWR, 0);
    if (fd >= 0)
	{
	if (ioctl (fd, TIOCNOTTY, NULL) < 0) perror ("ioctl (TIOCNOTTY)");
	close (fd);
	}
    }

    ttyname = pty(&MasterChannel);

    /* adjust terminal driver for Master Channel */
    setup_tty(MasterChannel);

    if (ttyname) 
	{
	ShellChannel = open(ttyname, O_RDWR, 0);
	if (ShellChannel < 0) perror("Shell Channel");
	}

    *master = MasterChannel;
    *slave = ShellChannel;
}

/*
 * 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);
    }
}

void fork_shell (char *name, char **args, char **env, int channel)
{
    int pid;

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

    if ((pid = fork ()) < 0)
	{
	fprintf (stderr, "Fork failed\n");
	exit (1);
	}

    if (pid == 0) {
	int cpid;

	cpid = getpid ();
	setpriority(0, cpid, 0);
	if (setpgrp (0, 0) < 0) perror ("setpgrp");
	
	if (channel >= 0) close(channel);
	channel = open(ptyname, O_RDWR, 0);

	vhangup();

	/* adjust terminal driver for Shell Channel */
	child_setup_tty(channel);

	dup2(channel, 0);
	dup2(channel, 1);
	dup2(channel, 2);
	close(channel);

	execve (name, args, env);

	_exit (1);
    }
}

/*
 * Create the information necessary for handling a new display.
 * The return value is the "rock" that should be given to
 * DPSAddFD() as the value to give to input_from_apps()
 *
 * (A "rock" is the CMU term for an item you hide information
 * underneath.)
 */

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