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.