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.