ftp.nice.ch/pub/next/tools/frontends/Emacs.2.1.N.bs.tar.gz#/Emacs-2.1/etermSupport.c

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

/*
 * Copyright 1990, John G. Myers
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#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;
}


/* 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, ShellChannel, PtyNumber;
    int pid;
    char	 c;

    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", 2);
	if (fd >= 0)
	  {
	      if (ioctl (fd, TIOCNOTTY, NULL) < 0)
		perror ("ioctl (TIOCNOTTY)");
	      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) {
	fprintf (stderr, "Can't connect subchannel\n");
	exit (1);
    }

    /* adjust terminal driver for Master Channel */
    {
	/* exclusive use of Master */
	if (ioctl (MasterChannel, FIOCLEX, NULL) < 0)
	  perror ("ioctl (FIOCLEX)");
    }

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

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

/*
 * 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) {
	fprintf (stderr, "Fork failed\n");
	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--)
	  (void) close(i);

	execve (name, args, env);
	write (2, "Couldn't exec emacs.\n", 21);
	exit (1);
    }
}

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