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. */
{
/* Exclusive use of Master. */
if (ioctl (MasterChannel, FIOCLEX, NULL) < 0)
NXLogError ("ioctl (FIOCLEX): %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.